3

Is there a way to expand a macro using a list of arguments? I tried using apply but then I get an error that the "function" my/x-becomes-nil is invalid.

(defmacro my/x-becomes-nil (variable x)
  `(if (eq ,variable ,x)
       (setq ,variable nil)))

(let ((q 2))
  (my/x-becomes-nil q 2)
  ;;(apply 'my/x-becomes-nil (list q 2)) ;; How to make this work?
  q)
3

2 Answers 2

3

No. As (elisp) Calling Functions tells us, for funcall (and it lets us know that apply is the same):

Special forms and macros are not allowed, because they make sense only when given the unevaluated argument expressions. funcall cannot provide these because, as we saw above, it never knows them in the first place.

I suggest that you think about what you are really trying to do, i.e., the reason why you think you need/want to apply a macro to a list of args. There might be an X-Y problem here.

2
  • I see. I don't quite see why the macro call is not possible since the arguments are not evaluated (I have a list of arguments or forms) so substituting the list of arguments into the macro definition should be possible theoretically.
    – Tohiko
    Commented Feb 1, 2021 at 15:56
  • 4
    funcall and apply are themselves functions -- so by the time they call their function argument, the arguments to be passed to that function have likewise already been evaluated. I.e. if you call (apply 'foo X Y Z) then 'foo, X, Y, and Z have all been evaluated before apply does anything at all. This is the "it never knows them in the first place" part of the quote -- the un-evaluated arguments are not seen by apply at all.
    – phils
    Commented Feb 2, 2021 at 6:09
0
(defmacro my/x-becomes-nil (&rest args)
  (let* ((two-args (= (length args) 2))
         (var (funcall (if two-args #'car #'caar) args))
         (val (funcall (if two-args #'cadr #'cadar) args)))
    `(when (eq ,var ,val)
       (setq ,var nil))))

Expands identically when called either as (my/x-becomes-nil q 2) or (my/x-becomes-nil (q 2)). Note that the list literal in the second case is not quoted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.