I am trying to call a macro (defined somewhere else; I can't change it), but I want to evaluate some of the arguments before the macro is expanded. Is this possible?

For example:

(defmacro foo (&rest args) (mapcar (lambda (a) (message "arg: %s" a)) args) nil)
(foo b (+ 1 1) c)
;; Prints:
;;   arg: b
;;   arg: (+ 1 1)
;;   arg: c
;; But I want:
;;   arg: b
;;   arg: 2
;;   arg: c

The only way I've found so far is:

(eval `(foo b ,(+ 1 1) c))

Is there a better way?

  • 4
    1. There's no way to ask an existing macro to evaluate its arguments when you call it (not doing so is one of the key properties of a macro). 2. Your example macro expands to nil and would trigger those messages only at expansion-time, so... that's weird. – phils May 15 '19 at 21:41
  • I agree that it's a bit weird. For context, I'm messing around with Doom Emacs' doom! macro, which I assume was written as such to avoid quoting all of its arguments. I'm trying to make some of my included packages conditional based on whether I am configured for running at work, at home, etc., but doom! is interpreting my (when ...) forms as package declarations. The eval trick above seems to hack around that. – 0x5453 May 16 '19 at 13:30
  • 4
    How about (let ((tmp (+ 1 1))) (foo b tmp c))? – kdb May 16 '19 at 22:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.