Common Lisp the Language, 2nd Edition

Next: Destructuring Up: Macros Previous: Macro Definition

# 8.2. Macro Expansion

The `macroexpand` function is the conventional means for expanding a macro call. A hook is provided for a user function to gain control during the expansion process.

[Function]
`macroexpand` `form` `&optional` `env` `
``macroexpand-1` `form` `&optional` `env`

If form is a macro call, then `macroexpand-1` will expand the macro call once and return two values: the expansion and `t`. If form is not a macro call, then the two values form and `nil` are returned.

A form is considered to be a macro call only if it is a cons whose car is a symbol that names a macro. The environment env is similar to that used within the evaluator (see `evalhook`); it defaults to a null environment. Any local macro definitions established within env by `macrolet` will be considered. If only form is given as an argument, then the environment is effectively null, and only global macro definitions (as established by `defmacro`) will be considered.

Macro expansion is carried out as follows. Once `macroexpand-1` has determined that a symbol names a macro, it obtains the expansion function for that macro. The value of the variable `*macroexpand-hook*` is then called as a function of three arguments: the expansion function, the form, and the environment env. The value returned from this call is taken to be the expansion of the macro call. The initial value of `*macroexpand-hook*` is `funcall`, and the net effect is to invoke the expansion function, giving it form and env as its two arguments.

X3J13 voted in June 1988 (FUNCTION-TYPE) to specify that the value of `*macroexpand-hook*` is first coerced to a function before being called as the expansion interface hook. Therefore its value may be a symbol, a lambda-expression, or any object of type `function`.

X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT) to specify that macro environment objects received by a `*macroexpand-hook*` function have only dynamic extent. The consequences are undefined if such objects are referred to outside the dynamic extent of that particular invocation of the hook function. This allows implementations to use somewhat more efficient techniques for representing environment objects.

(The purpose of `*macroexpand-hook*` is to facilitate various techniques for improving interpretation speed by caching macro expansions.)

X3J13 voted in June 1989 (MACRO-CACHING) to clarify that, while `*macroexpand-hook*` may be useful for debugging purposes, despite the original design intent there is currently no correct portable way to use it for caching macro expansions.

- Caching by displacement (performing a side effect on the macro-call form) won't work because the same (`eq`) macro-call form may appear in distinct lexical contexts. In addition, the macro-call form may be a read-only constant (see `quote` and also section 25.1).

- Caching by table lookup won't work because such a table would have to be keyed by both the macro-call form and the environment, but X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT) to permit macro environments to have only dynamic extent.

- Caching by storing macro-call forms and expansions within the environment object itself would work, but there are no portable primitives that would allow users to do this.

X3J13 also noted that, although there seems to be no correct portable way to use `*macroexpand-hook*` to cache macro expansions, there is no requirement that an implementation call the macro expansion function more than once for a given form and lexical environment.

X3J13 voted in March 1989 (SYMBOL-MACROLET-SEMANTICS) to specify that `macroexpand-1` will also expand symbol macros defined by `symbol-macrolet`; therefore a form may also be a macro call if it is a symbol. The vote did not address the interaction of this feature with the `*macroexpand-hook*` function. An obvious implementation choice is that the hook function is indeed called and given a special expansion function that, when applied to the form (a symbol) and env, will produce the expansion, just as for an ordinary macro; but this is only my suggestion.

The evaluator expands macro calls as if through the use of `macroexpand-1`; the point is that `eval` also uses `*macroexpand-hook*`.

`macroexpand` is similar to `macroexpand-1`, but repeatedly expands form until it is no longer a macro call. (In effect, `macroexpand` simply calls `macroexpand-1` repeatedly until the second value returned is `nil`.) A second value of `t` or `nil` is returned as for `macroexpand-1`, indicating whether the original form was a macro call.

[Variable]
`*macroexpand-hook*`

The value of `*macroexpand-hook*` is used as the expansion interface hook by `macroexpand-1`.

Next: Destructuring Up: Macros Previous: Macro Definition