dash.el icon indicating copy to clipboard operation
dash.el copied to clipboard

Consider defining -last-item and -first-item as generalised variables

Open Wilfred opened this issue 8 years ago • 6 comments

I'd like to be able to write:

(setf (-last-item some-list) new-value)

Rather than:

(setf (car (last some-list)) new-value)

Would you be open to a patch that did this?

Wilfred avatar Nov 05 '16 00:11 Wilfred

This gives me an idea... maybe we could add this interface also for "predicates" like -last or -first and similar commands... that would enable us to "find the element and modify it" in a universal way (basically simulating functions like --replace-first and similar).

Would such an API make sense?

Fuco1 avatar Nov 08 '16 11:11 Fuco1

I'm not sure what you're describing. Do you mean supporting something like this?

(setf (-first #'evenp some-list) 0)

Wilfred avatar Nov 08 '16 21:11 Wilfred

Exactly. That's equivalent to a hypothetical api (-replace-first #'evenp some-list 0) but with the advantage we don't have to add a version for each dash function which does something like this.

The disadvantage is that AFAIU setf is side-effect and dash is trying to be pure. Can you make a pure version of setf?

Fuco1 avatar Nov 09 '16 10:11 Fuco1

@Fuco1: cl-letf is pure:

(setq lst '(1 2 3))
(cl-letf (((-first-item lst) 0))
  (copy-list lst)) ;; => (0 2 3)
lst ;; => (1 2 3)

Without the copy-list, you'd get (1 2 3) back. You could put this into a macro:

(defmacro -replacef (lst place value)
  `(letf ((,place ,value))
     (copy-list lst)))

(-replacef lst (-first-item lst) 0) ;; => (0 2 3)

Of course, this is far from perfect, because you have to specify lst as well as place, meaning that the following won't work:

(-replacef '(1 2 3) (-first-item '(1 2 3)) 0) ;; => (1 2 3)

It's a start, anyhow.

daantjie avatar Nov 13 '16 19:11 daantjie

You can make a slight improvement, if you let --replacef be anaphoric.

(defmacro --replacef (lst place value)
  `(letf* ((it ,lst)
           (,place ,value))
     (copy-list it)))

(--replacef '(1 2 3) (-first-item it) 0) ;; => (0 2 3)

I've looked through some of the gv code, and I have a feeling that to make something like -replacef that doesn't require (effectively) specifying the list twice will be fairly involved (but I'll give it a good shot).

daantjie avatar Nov 14 '16 19:11 daantjie

This was partially implemented in #205

Fuco1 avatar Apr 24 '17 13:04 Fuco1