1

I was constructing a macro that nested another macro and I ran into something that confused me. If the backquoted macro was the last form in the defmacro it evaluated as expected. If added an additional result it wouldn't work without an explicit eval. I've written some toy examples to illustrate my confusion:

(defmacro my-test-macro (arg1)
  `(format "we have %s" ,arg1))

(defmacro my-test-macro2 (arg1)
  (let ((part1 `(format "we have %s" ,arg1)))
    (format "this is outside quote (%s)" part1)))

(defmacro my-test-macro3 (arg1)
  (let ((part1 (eval `(format "we have %s" ,arg1))))
    (format "this is outside quote (%s)" part1)))

(my-test-macro "test1")
"we have test1"

(my-test-macro2 "test2")
"this is outside quote ((format we have %s test2))"

(my-test-macro3 "test3")
"this is outside quote (we have test3)"

So was it bad practice not to eval the result for my backquote? In the wider context of elisp macros do they tend to just return a single form which gets automatically evaluated?

  • Neither my-test-macro2 nor my-test-macro3 would be typically called macros (they don't generate any source code, instead they produce a string). That aside (eval `(format "we have %s" ,arg1)) is exactly the same as (format "we have %s" arg1). In general, macros aren't meant to produce values, they are supposed to produce source code. – wvxvw May 22 '15 at 8:50
4

LISP is simple business:

  • function calls receive their arguments evaluated, their result is used verbatim
  • macro calls receive their arguments un-evaluated, their result is used evaluated

Other than that, you can almost look at macros as functions. In your case, since the arguments are strings, they're the same whether evaluated or not, so the difference between my-test-macro being a function or a macro is only in whether the result it returns will be evaluated or not.

Here's an example of a useful macro:

(defmacro when (cond &rest body)
  "If COND yields non-nil, do BODY, else return nil.
When COND yields non-nil, eval BODY forms sequentially and return
value of last one, or nil if there are none.
\(fn COND BODY...)"
  (declare (indent 1) (debug t))
  (list 'if cond (cons 'progn body)))

Note that it doesn't use a backquote at all. But it could, here's an equivalent implementation:

(defmacro when (cond &rest body)
  "If COND yields non-nil, do BODY, else return nil.
When COND yields non-nil, eval BODY forms sequentially and return
value of last one, or nil if there are none.
\(fn COND BODY...)"
  (declare (indent 1) (debug t))
  `(if ,cond
       (progn
         ,@body)))
| improve this answer | |

Your Answer

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

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