[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Why does my Macro get expanded 8 times?
- To: SLUG@WARBUCKS.AI.SRI.COM
- Subject: Why does my Macro get expanded 8 times?
- From: "Scott B. Layson" <gyro@KESTREL.ARPA>
- Date: Wed, 13 Jul 88 00:30:16 EDT
- In-reply-to: Charles Hornig's message of Tue, 12 Jul 88 11:24 EDT <19880712152404.1.HORNIG@WINTER.SCRC.Symbolics.COM>
Date: Tue, 12 Jul 88 11:24 EDT
From: Charles Hornig <Hornig@ALDERAAN.SCRC.Symbolics.COM>
Date: Mon, 11 Jul 88 22:33:39 PDT
From: gyro@kestrel.ARPA (Scott B. Layson)
To prevent multiple macro expansion, you could make your macro a
so-called "displacing" macro, using ZL:DEFMACRO-DISPLACE. This will
cause it to modify the the cons which is the head of the form that
invokes the macro (got that?), effectively caching the expansion
there. (Try it to see the details; it's really pretty
straightforward.)
SCRC folks: surely one of the ways you considered fixing the problem
was to make all macros displace in Phase I. Why doesn't this work?
Because displacing macros are the wrong thing in a language with lexical
scoping. This is because the expansion of a macro may depend on the
lexical environment at the time the expansion is done. The failing case
is where the expansion of one macro contains a macro invocation of a
second macro. See below:
(defmacro m1 ()
`(m2))
(defmacro m2 (&environment env)
(macroexpand '(m3) env))
(defun f1 ()
(macrolet ((m3 () '1))
(m1)))
(defun f2 ()
(macrolet ((m3 () '2))
(m1)))
Consider what would happen if M2 were a displacing macro. When F1 was
compiled, it would splice its expansion ('1) in place of the macro call
(the quoted constant in M1). When F2 was compiled, the wrong expansion
for M2 would be used.
Well geez, this scenario doesn't depend on lexical scoping or
MACROLET. All it requires is that M1 return a quoted constant call to
M2, and that M2 somehow be able to expand differently at different
times even though it accepts no arguments (e.g. it could gensym, or
receive information via special variables bound by COMPILER-LET).
So instead of displacing in the traditional way by bashing the head
cons of the macro form, Phase I could displace by bashing the car of
the cons that points to the macro form. It ought to do this anyway
because macros can expand to atoms. The traditional approach was
necessitated only, of course, by the fact that a pointer to the
"parent" cons (the one whose car is the macro form) is not available
to the macro body code.
Seems to me this *has* to be okay because nothing in CLtL specifies
that macros must be expanded more than once during compilation, nor
does it specify *when* they get expanded, except of course that the
rules for MACROLET must be followed.
-- Scott