Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--case-> macro? #197

Open
alphapapa opened this issue Oct 15, 2016 · 4 comments
Open

--case-> macro? #197

alphapapa opened this issue Oct 15, 2016 · 4 comments
Assignees
Labels
enhancement Suggestion to improve or extend existing behavior

Comments

@alphapapa
Copy link

alphapapa commented Oct 15, 2016

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.

@Fuco1
Copy link
Collaborator

Fuco1 commented Oct 15, 2016

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.

@Fuco1
Copy link
Collaborator

Fuco1 commented Oct 15, 2016

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).

@alphapapa
Copy link
Author

alphapapa commented Oct 16, 2016

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.

@Fuco1 Fuco1 self-assigned this Apr 12, 2018
@Fuco1 Fuco1 added the enhancement Suggestion to improve or extend existing behavior label Jul 26, 2018
@basil-conto
Copy link
Collaborator

Does #349 satisfy this feature request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Suggestion to improve or extend existing behavior
Projects
None yet
Development

No branches or pull requests

3 participants