FUZZ> (defvar *foo* nil)
*FOO*
FUZZ> (defmacro bar ()
(format t "foo: ~A" *foo*)
`(+ 1 1))
BAR
FUZZ> (defmacro bot ()
(let ((*foo* 17))
`(bar)))
BOT
FUZZ> (bot)
foo: NIL
My mental model (clearly wrong) of macro expansion says the following happens in order:
Run the macro expansion of bot (which binds *foo* to 17), run the macro expansion of bar, which prints the current value of *foo* (being 17), and returns the form (+ 1 1), which is not a macro, macro expansion time is now over, finally evaluate the form (+ 1 1), and returns 2.
Why am I wrong?
Is there an easy way to do what I intend?
When the REPL is told to evaluate
(bot), it first has to perform macroexpansion. It calls the macroexpansion functionbot, which means, in effect, evaluatingThat returns
(bar)and then the binding of fromletis unwound. Now we've got(bar).baris a macro, so it's time for another round of macroexpansion, which means evaluatingwhich prints
foo: NIL, and returns(+ 1 1).If you want the macroexpansion to be performed in the scope of some bindings, you'll need to call the macroexpansion function yourself. E.g., you can use macroexpand:
But, if you're going to do macroexpansion yourself, be sure to preserve environment arguments. In this case, a better definition of
bazwould be: