Usually, macros are expanded on behalf of the user as needed. Macro
expansion is an integral part of
can also expand macros at the REPL prompt via the
command; See Compile Commands.
Macros can also be expanded programmatically, via
but the details get a bit hairy for two reasons.
The first complication is that the result of macro-expansion isn’t
Scheme: it’s Tree-IL, Guile’s high-level intermediate language.
See Tree-IL. As “hygienic macros” can produce identifiers that are
distinct but have the same name, the output format needs to be able to
represent distinctions between variable identities and names. Again,
See Tree-IL, for all the details. The easiest thing is to just run
tree-il->scheme on the result of macro-expansion:
(macroexpand '(+ 1 2)) ⇒ #<tree-il (call (toplevel +) (const 1) (const 2))> (use-modules (language tree-il)) (tree-il->scheme (macroexpand '(+ 1 2))) ⇒ (+ 1 2)
The second complication involves
eval-when. As an example, what
would it mean to macro-expand the definition of a macro?
(macroexpand '(define-syntax qux (identifier-syntax 'bar))) ⇒ ?
The answer is that it depends who is macro-expanding, and why. Do you
define the macro in the current environment? Residualize a macro
definition? Both? Neither? The default is to expand in “eval” mode,
which means an
eval-when clauses will only proceed when
expand) is in its condition set. Top-level
macros will be
eval’d in the top-level environment.
In this way
(macroexpand foo) is equivalent to
(macroexpand foo 'e '(eval)). The second argument is the
'e for “eval”) and the third is the
eval-syntax-expanders-when parameter (only
eval in this default
But if you are compiling the macro definition, probably you want to
reify the macro definition itself. In that case you pass
the second argument to
macroexpand. But probably you want the
macro definition to be present at compile time as well, so you pass
'(compile load eval) as the esew parameter. In fact
(compile foo #:to 'tree-il) is entirely equivalent to
(macroexpand foo 'c '(compile load eval)); See The Scheme Compiler.
It’s a terrible interface; we know. The macroexpander is somewhat tricksy regarding modes, so unless you are building a macro-expanding tool, we suggest to avoid invoking it directly.