Abdulaziz Ghuloum <aghuloum@cee.ess.indiana.edu> wrote:
+---------------
| Rob Warnock wrote:
| > Sometimes I think that with all the bickering about macro style
| > we sometimes forget that Scheme & CL both share the amazing power
| > of lexical closures.
|
| In scheme, there is lexical scope for procedures and macros. In CL,
| there is lexical scope for procedures and dynamic scope for macros.
| In elisp, it's dynamic scope for both (no closures).
+---------------
Hmmm... Digging into this a bit, I think that for CL, it's actually a
bit *worse*[1] than if it were really just "dynamic scope for macros":
http://alu.org/HyperSpec/Body/speope_fletcm_scm_macrolet.html
Special Operator FLET, LABELS, MACROLET
...
macrolet
The macro-expansion functions defined by macrolet are defined in the
lexical environment in which the macrolet form appears. Declarations
and macrolet and symbol-macrolet definitions affect the local macro
definitions in a macrolet, but the consequences are undefined if
the local macro definitions reference any local variable or function
bindings that are visible in that lexical environment.
And then they give an example that is very close to Pascal_C's, except
using the LAMBDA-bound variables of a DEFUN as the outer ones that
can't be referenced instead of Pascal's LET-bound outer variable.
To repeat what Pascal Costanza <pc@p-cos.net> wrote:
+---------------
| (let ((x 42))
| (macrolet ((foo () 'x))
| (let ((x 4711))
| (foo))))
|
| Now assume you're not allowed to change the names of the x variable
| bindings. In a defmacro-style macro system, there is no way that you can
| ensure that the code to which foo expands refers to the outer x by just
| changing the macro definition. Whatever you may try, the outer x will be
| shadowed by the inner x in the inner expansion of foo.
+---------------
After reading the above CLHS quote, I now think that's probably correct.
The MACROLET definition cannot itself capture the lexical value of the
outer X [because it probably doesn't exist yet when the macro expansion
function is closed over]. You would have to use some *other* binding
form to perform that capture at :EXECUTE time [such as the FLETs I
showed previously], but then the MACROLET definition could certainly
expand into a *reference* to that other binding form. And the definition
of the macro expansion of that reference can even be done *before* the
other binding form is encountered:
> (let ((x 42))
(macrolet ((foo () '(list y x)))
(let ((y x))
(let ((x 4711))
(foo)))))
(42 4711)
>
*Or* after:
> (let ((x 42))
(let ((y x))
(macrolet ((foo () '(list y x)))
(let ((x 4711))
(foo)))))
(42 4711)
>
But the point being that in either case the macro *definition* cannot
reference the :EXECUTE lexical environment, only its *expansion* can.
Oh, well...
-Rob
[1] The reason I say this is "worse" than "just dynamic scope" is that
the dynamic values of variables in the macro *definition* might be
those at compile time, which could be altogether different than the
dynamic values of those very same variables at runtime (:EXECUTE).
Pascal Bourguignon's article in the "passing values from compile-time
to load-time" thread <news:87lk5ke92b.fsf@thalassa.informatimago.com>
hints at this when he said:
When a macro is executing, the situation is :EXECUTE.
but I don't think he made it clear enough there -- at least, not
for the purposes of *this* discussion -- that the macro is probably
executing at compile time, and even though "the situation is :EXECUTE"
during its execution the dynamic environment at that time is the
environment of the *compiler*, which is not (or not necessarily)
the dynamic environment in which the code being compiled will
itself :EXECUTE.
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607