macroscommon-lispspecial-variables

How to establish a variable binding that will be active during macroexpansion time?


Let's define a function, the body of which contains the macro, which will be expanded at some unspecified time and will use a global dynamic value of *test* during this process.

> (defvar *test* nil)
> (defmacro body ()
    `(print ,*test*))
> (defun test ()
    (body))
> (test)
NIL

But what if I want to bind *test* to, say, 1 during function definition, so that the macroexpansion operated with this binding in effect and the call to test produced 1 instead of NIL.

Just wrapping defun in let doesn't work:

> (let ((*test* 1))
    (defun test ()
      (body)))
> (test)
NIL

Probably, it is related to this line in Hyperspec:

defun is not required to perform any compile-time side effects

But are there any other ways to do that?


Solution

  • As you yourself write, macro are expanded at unspecified time. In my SBCL the macro is expanded before the whole form is evaluated, which means before the LET binding is in effect. For some interpreters the macro might be expanded when the function is executed, after the binding expired.

    Early versions of what became Common Lisp included such mechanism through COMPILER-LET, but it has been removed. See COMPILER-LET-CONFUSION issue for more detail. Lexically some of the effects can be achieved using MACROLET/SYMBOL-MACROLET. Dynamically it is difficult to make this work sanely and I would recommend rethinking the approach, if using actual dynamic bindings seem necessary.