Lexical environment
Using eval
inside a macro is bad practice. Sure, the following works:
(macroexpand-1 '(macrotest a))
; => (user/d (b c))
... but then, this does not work as expected:
(macroexpand-1 '(let [a "oh no"]
(macrotest a)))
; => (user/d (b c))
Surely you would like the macro to evaluate a
as it was defined locally, not using the global variable bound to it, but you cannot because the macro does not evaluate v
in the right lexical context. And this is the key to understanding macros: they take code and produce code; any data manipulated by that code is not available to you yet. In other words, the moment at which macros are expanded might be totally unrelated to the time their resulting code is evaluated: anything you evaluate while a macro is being executed is probably evaluated too soon w.r.t. the relevance of your data.
What do you want to do?
There is a form named macrotest
which should accepts an argument, v
and then perform as-if you had form d
applied to it. But:
(macrotest (b c))
should not evaluate (b c)
, just copy it untouched to produce (d (b c))
.
(macrotest a)
should evaluate a
, which results in a quoted form, and place that form in the resulting code, also returning (d (b c))
.
You have a problem here, because the meaning changes radically in one or the other case. Either you evaluate an argument, in which case you must quote (b c)
and you write:
(defmacro macrotest [v] `(d ~v))
... which requires that d
is ready to handle quoted arguments; or you are okay with the argument being not evaluated.
With the same d
as above, you can quote the argument explicitly:
(defmacro macrotest [v] `(d '~v))
However, if d
itself is a macro that does not evaluate its argument, you have to avoid the quote in front of ~v
.