dash.el
dash.el copied to clipboard
--case-> macro?
I'm still an elisp noob, so this is probably a bad idea and I just don't realize it yet. :) (I did search the issue tracker but I didn't find anything quite like this.)
What do you think about this macro?
(defmacro --case-> (value &rest cond-forms)
`(let ((it ,value))
(dolist (form ',cond-forms it)
(when (eval (car form))
(setq it (eval (cadr form)))))))
Used like this:
(--case-> (list 1 2 3)
(t (nreverse it))
(t (--map (* 2 it) it))) ; => (6 4 2)
I think it could be useful when handling option arguments to a function, where each option has the potential to mutate the result.
I thought that --> with when would work, like this:
(--> (list 1 2 3)
(if t (nreverse it) it)
(it t (--map (* 2 it) it) it))
But instead I get an error:
Debugger entered--Lisp error: (void-variable it)
(mapcar (function (lambda (it) (* 2 it))) it)
(progn (mapcar (function (lambda (it) (* 2 it))) it))
(if t (progn (mapcar (function (lambda (it) (* 2 it))) it)))
eval((if t (progn (mapcar (function (lambda (it) (* 2 it))) it))) nil)
And I don't understand the macro expansion, which leaves out everything except the last form:
(if t
(progn
(--map
(* 2 it)
it)))
But even if that did work, having to write (if COND FORM IT) instead of (COND FORM) is much more verbose, so it seems like (--case-> ... could still be useful.
There's also this one, which handles multiple forms:
(defmacro --case-multi-> (value &rest cond-forms)
`(let ((it ,value))
(dolist (form ',cond-forms it)
(when (eval (car form))
(dolist (f (cdr form))
(setq it (eval f)))))))
Used like:
(--case-multi-> (list 1 2 3)
(t (nreverse it))
(t (--map (* 2 it) it)
(--map (+ 1 it) it))) ; => (7 5 3)
Thanks for your work on Dash.
So if I understand it correctly, a more "proper" example could be
(let ((options (list :reverse t :pop nil :double t)))
(--case-> (list 1 2 3)
((plist-get options :reverse) (nreverse it))
((plist-get options :pop) (pop it))
((plist-get options :double) (--map (* 2 it) it)))) ; => (6 4 2)
Is this what you mean? I can see the usefulness but I'm thinking if it couldn't be solved in some other way already available.
As for the implementation, you absolutely shouldn't need to use eval. In general, using eval means you are doing something evil. Try to rewrite it in a way you could avoid that (consider it an exercise in elisp :D).
Haha, thanks. My experience writing macros is very limited.
By the way, what made me think of it is this: https://github.com/alphapapa/mosey.el/blob/master/mosey.el#L150
Here I need to reverse the result if backward is set, and it seems ugly to do it the way I have there, by setting the variable again with an if. I wanted a way to simply wrap the original value that would reverse it if necessary. Of course, with a case like this, it would hardly justify writing a macro, but it made me wonder if a macro that could do this would be generally useful in more complicated cases.
Does #349 satisfy this feature request?