From: Pascal Costanza
Subject: Closer to macro hygiene
Date: 
Message-ID: <4eh6ooF1ekvb5U1@individual.net>
Hi,

I am experimenting with an idea how to achieve better macro hygiene in 
Common Lisp - especially referential transparency.

As far as I can tell, the following code should work:

(define-symbol-macro %aliases '())

(defmacro slet ((&rest bindings) &body body &environment env)
   (let ((aliases (loop for binding in bindings
                        for binding-name = (etypecase binding
                                             (cons (car binding))
                                             (symbol binding))
                        collect `(,binding-name
                                  ,(copy-symbol binding-name)))))
     `(let ,(loop for binding in bindings
                  for alias in aliases
                  collect (cons (cadr alias) (etypecase binding
                                               (cons (cdr binding))
                                               (symbol 'nil))))
        (symbol-macrolet ,aliases
          (symbol-macrolet
            ((%aliases ',(append aliases
                                 (cadr (macroexpand '%aliases env)))))
            ,@body)))))

(defmacro slet* ((&rest bindings) &body body)
   (if bindings
     `(slet (,(car bindings))
        (slet* (,@(cdr bindings)) ,@body))
     `(progn ,@body)))

(defun test ()
   (slet* ((x 1) (y 2))
     (macrolet ((some-macro ()
                  `(progn
                     (print ,(cadr (assoc 'x %aliases)))
                     (print ,(cadr (assoc 'y %aliases)))
                     (print x)
                     (print y))))
       (slet* ((x 3) (y 4))
         (some-macro)))))

The expected output is:
1
2
3
4

This code indeed works in CMUCL, clisp, LispWorks, OpenMCL and SBCL, as 
well as in Allegro and ecl in interpreted mode. However, in Allegro and 
ecl this code doesn't work when compiled, but produces the following 
output instead:
NIL
NIL
3
4

When I use "proper" macros instead of symbol macros for %aliases, the 
code works in compiled Allegro, but still not in compiled ecl.

I am pretty sure that the code is correct, considering the HyperSpec 
entry for macrolet which states that "macrolet and symbol-macrolet 
definitions affect the local macro definitions in a macrolet".

Or am I missing something?


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/

From: Kaz Kylheku
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <1149530704.320226.246970@u72g2000cwu.googlegroups.com>
Pascal Costanza wrote:
> (defun test ()
>    (slet* ((x 1) (y 2))
>      (macrolet ((some-macro ()
>                   `(progn
>                      (print ,(cadr (assoc 'x %aliases)))
>                      (print ,(cadr (assoc 'y %aliases)))
>                      (print x)
>                      (print y))))
>        (slet* ((x 3) (y 4))
>          (some-macro)))))

I think the problem here is that the unquoted ,(cadr ...) are evaluated
at macro-expansion time. You're expecting the macro-expansion-time
evaluations of (some-macro) to have access to the information hooked
thorugh the %aliases symbol macro set up by the code produced by
surrounding slet*. But that code is what is being generated at
macro-expansion-time. I.e. this appears to be a classic case of writing
a macro whose expansion logic tries to depend on things that are
established when macro-expansion is done.

> I am pretty sure that the code is correct, considering the HyperSpec
> entry for macrolet which states that "macrolet and symbol-macrolet
> definitions affect the local macro definitions in a macrolet".

Maybe the problem is that your macro definition isn't in a macrolet.
It's in a SLET*.

It's not known that there is a macrolet there until SLET* itself is
expanded.

What does the code produce if you manually replace the SLET* by its
intended expansion?

:)
From: Ron Garret
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <rNOSPAMon-B5E4B5.12162205062006@news.gha.chartermi.net>
In article <························@u72g2000cwu.googlegroups.com>,
 "Kaz Kylheku" <········@gmail.com> wrote:

> Pascal Costanza wrote:
> > (defun test ()
> >    (slet* ((x 1) (y 2))
> >      (macrolet ((some-macro ()
> >                   `(progn
> >                      (print ,(cadr (assoc 'x %aliases)))
> >                      (print ,(cadr (assoc 'y %aliases)))
> >                      (print x)
> >                      (print y))))
> >        (slet* ((x 3) (y 4))
> >          (some-macro)))))
> 
> I think the problem here is that the unquoted ,(cadr ...)

Nope, it's a bug in the ACL compiler:

CL-USER(1): (define-symbol-macro x 1)
X
CL-USER(2): (defun foo ()
  (symbol-macrolet ((x 2))
    (macrolet ((m () x))
      (m))))
FOO
CL-USER(3): (foo)
2
CL-USER(4): (compile 'foo)
FOO
NIL
NIL
CL-USER(5): (foo)
1
CL-USER(6):
From: Pascal Costanza
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <4ejh05F1f7220U1@individual.net>
Ron Garret wrote:
> In article <························@u72g2000cwu.googlegroups.com>,
>  "Kaz Kylheku" <········@gmail.com> wrote:
> 
>> Pascal Costanza wrote:
>>> (defun test ()
>>>    (slet* ((x 1) (y 2))
>>>      (macrolet ((some-macro ()
>>>                   `(progn
>>>                      (print ,(cadr (assoc 'x %aliases)))
>>>                      (print ,(cadr (assoc 'y %aliases)))
>>>                      (print x)
>>>                      (print y))))
>>>        (slet* ((x 3) (y 4))
>>>          (some-macro)))))
>> I think the problem here is that the unquoted ,(cadr ...)
> 
> Nope, it's a bug in the ACL compiler:
> 
> CL-USER(1): (define-symbol-macro x 1)
> X
> CL-USER(2): (defun foo ()
>   (symbol-macrolet ((x 2))
>     (macrolet ((m () x))
>       (m))))
> FOO
> CL-USER(3): (foo)
> 2
> CL-USER(4): (compile 'foo)
> FOO
> NIL
> NIL
> CL-USER(5): (foo)
> 1
> CL-USER(6):

Ah, that's a much simpler and better test case. Thanks.


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Peter Seibel
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <m2y7wbfivz.fsf@gigamonkeys.com>
Pascal Costanza <··@p-cos.net> writes:

> Ron Garret wrote:
>> In article <························@u72g2000cwu.googlegroups.com>,
>>  "Kaz Kylheku" <········@gmail.com> wrote:
>> 
>>> Pascal Costanza wrote:
>>>> (defun test ()
>>>>    (slet* ((x 1) (y 2))
>>>>      (macrolet ((some-macro ()
>>>>                   `(progn
>>>>                      (print ,(cadr (assoc 'x %aliases)))
>>>>                      (print ,(cadr (assoc 'y %aliases)))
>>>>                      (print x)
>>>>                      (print y))))
>>>>        (slet* ((x 3) (y 4))
>>>>          (some-macro)))))
>>> I think the problem here is that the unquoted ,(cadr ...)
>> Nope, it's a bug in the ACL compiler:
>> CL-USER(1): (define-symbol-macro x 1)
>> X
>> CL-USER(2): (defun foo ()
>>   (symbol-macrolet ((x 2))
>>     (macrolet ((m () x))
>>       (m))))
>> FOO
>> CL-USER(3): (foo)
>> 2
>> CL-USER(4): (compile 'foo)
>> FOO
>> NIL
>> NIL
>> CL-USER(5): (foo)
>> 1
>> CL-USER(6):
>
> Ah, that's a much simpler and better test case. Thanks.

I'm wondering if someone from Franz is going to pipe up and explain
that this isn't a bug but a consequence of the separation of
compilation environment and evaluation environments. Note that the
following variation "works":

  CL-USER> (define-symbol-macro x 1)
  X
  CL-USER> x
  1
  CL-USER> (defun foo ()
             (symbol-macrolet ((x 2))
               (macrolet ((m () 'x))
                 (m))))

  FOO
  CL-USER> (foo)
  2
  CL-USER> (compile 'foo)
  FOO
  NIL
  NIL
  CL-USER> (foo)
  2

In Ron's example it's the *value* of X that's being used as the
expansion of M not X itself. Note also:

  CL-USER> (defun foo ()
             (symbol-macrolet ((x 2))
               (macrolet ((m (&environment env) (macroexpand 'x env)))
                 (m))))
  FOO
  CL-USER> (compile 'foo)
  FOO
  NIL
  NIL
  CL-USER> (foo)
  2
  CL-USER> (defun foo ()
             (symbol-macrolet ((x 2))
               (macrolet ((m () (macroexpand 'x)))
                 (m))))
  FOO
  CL-USER> (compile 'foo)
  FOO
  NIL
  NIL
  CL-USER> (foo)
  1

Recall two points from CLHS Sec 3.2.1:

  "The compilation environment is used as the environment argument to
  macro expanders called by the compiler."

  "The evaluation environment is a run-time environment in which macro
  expanders and code specified by eval-when to be evaluated are
  evaluated. All evaluations initiated by the compiler take place in
  the evaluation environment."

It seems that perhaps what's happening here is the SYMBOL-MACROLET of
X modifies the compilation environment which, in Allegro, IIRC, is
distinct from the evaluation environment. Thus in Ron's original
example, when the macroexpansion of (M), ends up running a function
that looks something like:

  (lambda (form env) x)

and this function is run in the evaluation environment where the only
visible binding for X is the global DEFINE-SYMBOL-MACRO definition so
the expansion of (M) is 1.

However in my version where X is quoted, the expansion function is
something like:

  (lambda (form env) 'x)

so the expansion is the symbol X which is then compiled in the
compilation environment where the SYMBOL-MACROLET definition is
visible so X is macro expanded into 2.

But I'm just making this up--hopefully someone from Franz will chime
in to say whether I'm on crack or not.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Duane Rettig
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <o0d5dn5lok.fsf@franz.com>
Peter Seibel <·····@gigamonkeys.com> writes:

> But I'm just making this up--hopefully someone from Franz will chime
> in to say whether I'm on crack or not.

I think I was taking the same stguff you were, but fortunately I got
rehabilitated by one of my colleagues :-)

> Pascal Costanza <··@p-cos.net> writes:
>
>> Ron Garret wrote:
>>> In article <························@u72g2000cwu.googlegroups.com>,
>>>  "Kaz Kylheku" <········@gmail.com> wrote:
>>> 
>>>> Pascal Costanza wrote:
>>>>> (defun test ()
>>>>>    (slet* ((x 1) (y 2))
>>>>>      (macrolet ((some-macro ()
>>>>>                   `(progn
>>>>>                      (print ,(cadr (assoc 'x %aliases)))
>>>>>                      (print ,(cadr (assoc 'y %aliases)))
>>>>>                      (print x)
>>>>>                      (print y))))
>>>>>        (slet* ((x 3) (y 4))
>>>>>          (some-macro)))))
>>>> I think the problem here is that the unquoted ,(cadr ...)
>>> Nope, it's a bug in the ACL compiler:
>>> CL-USER(1): (define-symbol-macro x 1)
>>> X
>>> CL-USER(2): (defun foo ()
>>>   (symbol-macrolet ((x 2))
>>>     (macrolet ((m () x))
>>>       (m))))
>>> FOO
>>> CL-USER(3): (foo)
>>> 2
>>> CL-USER(4): (compile 'foo)
>>> FOO
>>> NIL
>>> NIL
>>> CL-USER(5): (foo)
>>> 1
>>> CL-USER(6):
>>
>> Ah, that's a much simpler and better test case. Thanks.
>
> I'm wondering if someone from Franz is going to pipe up and explain
> that this isn't a bug but a consequence of the separation of
> compilation environment and evaluation environments.

This was my initial reaction, but in fact a symbol-macrolet acts more
like a function in that there is no "evaluation" - it is just a substitution.

> Note that the
> following variation "works":
>
>   CL-USER> (define-symbol-macro x 1)
>   X
>   CL-USER> x
>   1
>   CL-USER> (defun foo ()
>              (symbol-macrolet ((x 2))
>                (macrolet ((m () 'x))
>                  (m))))
>
>   FOO
>   CL-USER> (foo)
>   2
>   CL-USER> (compile 'foo)
>   FOO
>   NIL
>   NIL
>   CL-USER> (foo)
>   2
>
> In Ron's example it's the *value* of X that's being used as the
> expansion of M not X itself. Note also:

But if symbol-macrolet substitution has been done, then there is no X to
evaluate! 

While I was on the same stuff you're on :-),  I found it irritating that
people were qouting only part of the relevant paragraph:  "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 not what I thought was the relevant portion, immediately
following:

"but the consequences are undefined if the local macro definitions
reference any local variable or function bindings that are visible
in that lexical environment."

But if we follow our addiction all the way through - The definition
of "variable" has a definition and a reference (3.1.2.1.1, Symbols as
Forms), whose first sentence is "If a form is a symbol, then it is
either a symbol macro or a variable."  This implies that symbol macros
are not variables - they only _look_ like variables.

Another source of potential confusion is in the description of
symbol-macrolet itself: "Each reference to symbol as a variable within
the lexical scope of symbol-macrolet is expanded by the normal macro
expansion process...".  This might be taken to be that the symbol represents
a variable, but in fact it is only distinguishing between functional
and non-functional positions in code (i.e. "symbol _as_ variable",
as opposed to "symbol which _is_ a variable".)

>   CL-USER> (defun foo ()
>              (symbol-macrolet ((x 2))
>                (macrolet ((m (&environment env) (macroexpand 'x env)))
>                  (m))))
>   FOO
>   CL-USER> (compile 'foo)
>   FOO
>   NIL
>   NIL
>   CL-USER> (foo)
>   2
>   CL-USER> (defun foo ()
>              (symbol-macrolet ((x 2))
>                (macrolet ((m () (macroexpand 'x)))
>                  (m))))
>   FOO
>   CL-USER> (compile 'foo)
>   FOO
>   NIL
>   NIL
>   CL-USER> (foo)
>   1
>
> Recall two points from CLHS Sec 3.2.1:
>
>   "The compilation environment is used as the environment argument to
>   macro expanders called by the compiler."
>
>   "The evaluation environment is a run-time environment in which macro
>   expanders and code specified by eval-when to be evaluated are
>   evaluated. All evaluations initiated by the compiler take place in
>   the evaluation environment."
>
> It seems that perhaps what's happening here is the SYMBOL-MACROLET of
> X modifies the compilation environment which, in Allegro, IIRC, is
> distinct from the evaluation environment. Thus in Ron's original
> example, when the macroexpansion of (M), ends up running a function
> that looks something like:
>
>   (lambda (form env) x)
>
> and this function is run in the evaluation environment where the only
> visible binding for X is the global DEFINE-SYMBOL-MACRO definition so
> the expansion of (M) is 1.
>
> However in my version where X is quoted, the expansion function is
> something like:
>
>   (lambda (form env) 'x)
>
> so the expansion is the symbol X which is then compiled in the
> compilation environment where the SYMBOL-MACROLET definition is
> visible so X is macro expanded into 2.

The real question is whether a symbol-macrolet substitution is in fact
an evaluation.  As I've harped on before, and often people (not necessarily
you) are lazy in distinguishing when macro expansion occurs, (they will
say that macro expansion occurs at compile time or evaluation time, when it
really occurs at macroexpand time, which is neither of the former, but
sub-times of each).  So symbol-macro expansion does not necessarily involve
actual evaluation, at least not in the normal sense.

I actually found the source of the bug, and you can see it for yourself in
the implementation of Environments Access; when a macrolet expands its
definition at compile-time, it creates an environment called a ":macros-only"
kind of environment, and when the form and environment are passed on to an
evaluator to be processed, the lexical environment is copied to provide the
proper context within which to evaluate (i.e. macroexpand, since there must
be no lexical environment except for macros and symbol-macros).  But if
you look at the code for copy-enviironment in environ.cl, the macros-only case
is only copying macros; it is not copying symbol-macros.  Thus, the local
symbol-macro definition (i.e. the symbol-macrolet) is not being seen.


> But I'm just making this up--hopefully someone from Franz will chime
> in to say whether I'm on crack or not.

Down from your high, yet?  I'm there, now.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Pascal Costanza
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <4ejn0eF1f97oiU1@individual.net>
Duane Rettig wrote:

> The real question is whether a symbol-macrolet substitution is in fact
> an evaluation.  As I've harped on before, and often people (not necessarily
> you) are lazy in distinguishing when macro expansion occurs, (they will
> say that macro expansion occurs at compile time or evaluation time, when it
> really occurs at macroexpand time, which is neither of the former, but
> sub-times of each).  So symbol-macro expansion does not necessarily involve
> actual evaluation, at least not in the normal sense.
> 
> I actually found the source of the bug, and you can see it for yourself in
> the implementation of Environments Access; when a macrolet expands its
> definition at compile-time, it creates an environment called a ":macros-only"
> kind of environment, and when the form and environment are passed on to an
> evaluator to be processed, the lexical environment is copied to provide the
> proper context within which to evaluate (i.e. macroexpand, since there must
> be no lexical environment except for macros and symbol-macros).  But if
> you look at the code for copy-enviironment in environ.cl, the macros-only case
> is only copying macros; it is not copying symbol-macros.  Thus, the local
> symbol-macro definition (i.e. the symbol-macrolet) is not being seen.
> 
> 
>> But I'm just making this up--hopefully someone from Franz will chime
>> in to say whether I'm on crack or not.
> 
> Down from your high, yet?  I'm there, now.

The problem with you junkies is that it's never clear what you are 
actually saying.

So, is this a bug or not? ;)


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Ron Garret
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <rNOSPAMon-936D2E.14513105062006@news.gha.chartermi.net>
In article <···············@individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Duane Rettig wrote:
> 
> > The real question is whether a symbol-macrolet substitution is in fact
> > an evaluation.  As I've harped on before, and often people (not necessarily
> > you) are lazy in distinguishing when macro expansion occurs, (they will
> > say that macro expansion occurs at compile time or evaluation time, when it
> > really occurs at macroexpand time, which is neither of the former, but
> > sub-times of each).  So symbol-macro expansion does not necessarily involve
> > actual evaluation, at least not in the normal sense.
> > 
> > I actually found the source of the bug, and you can see it for yourself in
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > the implementation of Environments Access; when a macrolet expands its
> > definition at compile-time, it creates an environment called a 
> > ":macros-only"
> > kind of environment, and when the form and environment are passed on to an
> > evaluator to be processed, the lexical environment is copied to provide the
> > proper context within which to evaluate (i.e. macroexpand, since there must
> > be no lexical environment except for macros and symbol-macros).  But if
> > you look at the code for copy-enviironment in environ.cl, the macros-only 
> > case
> > is only copying macros; it is not copying symbol-macros.  Thus, the local
> > symbol-macro definition (i.e. the symbol-macrolet) is not being seen.
> > 
> > 
> >> But I'm just making this up--hopefully someone from Franz will chime
> >> in to say whether I'm on crack or not.
> > 
> > Down from your high, yet?  I'm there, now.
> 
> The problem with you junkies is that it's never clear what you are 
> actually saying.
> 
> So, is this a bug or not? ;)

Yes.  See the highlighted passage above.

rg
From: Pascal Costanza
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <4ejiuhF1esmtvU1@individual.net>
Peter Seibel wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> Ron Garret wrote:
>>> In article <························@u72g2000cwu.googlegroups.com>,
>>>  "Kaz Kylheku" <········@gmail.com> wrote:
>>>
>>>> Pascal Costanza wrote:
>>>>> (defun test ()
>>>>>    (slet* ((x 1) (y 2))
>>>>>      (macrolet ((some-macro ()
>>>>>                   `(progn
>>>>>                      (print ,(cadr (assoc 'x %aliases)))
>>>>>                      (print ,(cadr (assoc 'y %aliases)))
>>>>>                      (print x)
>>>>>                      (print y))))
>>>>>        (slet* ((x 3) (y 4))
>>>>>          (some-macro)))))
>>>> I think the problem here is that the unquoted ,(cadr ...)
>>> Nope, it's a bug in the ACL compiler:
>>> CL-USER(1): (define-symbol-macro x 1)
>>> X
>>> CL-USER(2): (defun foo ()
>>>   (symbol-macrolet ((x 2))
>>>     (macrolet ((m () x))
>>>       (m))))
>>> FOO
>>> CL-USER(3): (foo)
>>> 2
>>> CL-USER(4): (compile 'foo)
>>> FOO
>>> NIL
>>> NIL
>>> CL-USER(5): (foo)
>>> 1
>>> CL-USER(6):
>> Ah, that's a much simpler and better test case. Thanks.
> 
> I'm wondering if someone from Franz is going to pipe up and explain
> that this isn't a bug but a consequence of the separation of
> compilation environment and evaluation environments. Note that the
> following variation "works":
> 
>   CL-USER> (define-symbol-macro x 1)
>   X
>   CL-USER> x
>   1
>   CL-USER> (defun foo ()
>              (symbol-macrolet ((x 2))
>                (macrolet ((m () 'x))
>                  (m))))
> 
>   FOO
>   CL-USER> (foo)
>   2
>   CL-USER> (compile 'foo)
>   FOO
>   NIL
>   NIL
>   CL-USER> (foo)
>   2
> 
> In Ron's example it's the *value* of X that's being used as the
> expansion of M not X itself. Note also:
> 
>   CL-USER> (defun foo ()
>              (symbol-macrolet ((x 2))
>                (macrolet ((m (&environment env) (macroexpand 'x env)))
>                  (m))))
>   FOO
>   CL-USER> (compile 'foo)
>   FOO
>   NIL
>   NIL
>   CL-USER> (foo)
>   2
>   CL-USER> (defun foo ()
>              (symbol-macrolet ((x 2))
>                (macrolet ((m () (macroexpand 'x)))
>                  (m))))
>   FOO
>   CL-USER> (compile 'foo)
>   FOO
>   NIL
>   NIL
>   CL-USER> (foo)
>   1
> 
> Recall two points from CLHS Sec 3.2.1:
> 
>   "The compilation environment is used as the environment argument to
>   macro expanders called by the compiler."
> 
>   "The evaluation environment is a run-time environment in which macro
>   expanders and code specified by eval-when to be evaluated are
>   evaluated. All evaluations initiated by the compiler take place in
>   the evaluation environment."
> 
> It seems that perhaps what's happening here is the SYMBOL-MACROLET of
> X modifies the compilation environment which, in Allegro, IIRC, is
> distinct from the evaluation environment. Thus in Ron's original
> example, when the macroexpansion of (M), ends up running a function
> that looks something like:
> 
>   (lambda (form env) x)
> 
> and this function is run in the evaluation environment where the only
> visible binding for X is the global DEFINE-SYMBOL-MACRO definition so
> the expansion of (M) is 1.
> 
> However in my version where X is quoted, the expansion function is
> something like:
> 
>   (lambda (form env) 'x)
> 
> so the expansion is the symbol X which is then compiled in the
> compilation environment where the SYMBOL-MACROLET definition is
> visible so X is macro expanded into 2.
> 
> But I'm just making this up--hopefully someone from Franz will chime
> in to say whether I'm on crack or not.

But the HyperSpec entry for macrolet clearly says that surrounding 
symbol-macrolet and macrolet definitions have an effect on the macro body.

So in...

(symbol-macrolet ((x 2))
   (macrolet ((m () x))
     (m)))

...the body of m, which is an evaluation of x at macroexpansion time, 
should be expanded in an environment in which the local definition for x 
is in effect.

Also note that the respective macrolet version works correctly:

CL-USER(10): (defmacro x () 1)
X
CL-USER(11): (defun bar ()
                (macrolet ((x () 2))
                  (macrolet ((m () (x)))
                    (m))))
BAR
CL-USER(12): (bar)
2
CL-USER(13): (compile 'bar)
BAR
NIL
NIL
CL-USER(14): (bar)
2



Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pascal Costanza
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <4ejd9jF1e8quiU1@individual.net>
Kaz Kylheku wrote:
> Pascal Costanza wrote:
>> (defun test ()
>>    (slet* ((x 1) (y 2))
>>      (macrolet ((some-macro ()
>>                   `(progn
>>                      (print ,(cadr (assoc 'x %aliases)))
>>                      (print ,(cadr (assoc 'y %aliases)))
>>                      (print x)
>>                      (print y))))
>>        (slet* ((x 3) (y 4))
>>          (some-macro)))))
> 
> I think the problem here is that the unquoted ,(cadr ...) are evaluated
> at macro-expansion time. You're expecting the macro-expansion-time
> evaluations of (some-macro) to have access to the information hooked
> thorugh the %aliases symbol macro set up by the code produced by
> surrounding slet*. But that code is what is being generated at
> macro-expansion-time. I.e. this appears to be a classic case of writing
> a macro whose expansion logic tries to depend on things that are
> established when macro-expansion is done.
> 
>> I am pretty sure that the code is correct, considering the HyperSpec
>> entry for macrolet which states that "macrolet and symbol-macrolet
>> definitions affect the local macro definitions in a macrolet".
> 
> Maybe the problem is that your macro definition isn't in a macrolet.
> It's in a SLET*.
> 
> It's not known that there is a macrolet there until SLET* itself is
> expanded.

...but the (slet* ...) must be expanded before anything else that it 
encloses, right? The result of macroexpanding (slet* ...) should be 
processed in the same way as if I would write the macroexpansion of 
(slet* ...) directly.

> What does the code produce if you manually replace the SLET* by its
> intended expansion?

Good idea, but I indeed get the same result, both in Allegro and ecl. 
The changed test code is as follows:

(defun test2 ()
   (let ((-x- 1) (-y- 2))
     (symbol-macrolet ((x -x-) (y -y-))
       (symbol-macrolet ((%aliases '((x -x-) (y -y-))))
         (macrolet ((some-macro ()
                      `(progn
                         (print ,(cadr (assoc 'x %aliases)))
                         (print ,(cadr (assoc 'y %aliases)))
                         (print x)
                         (print y))))
           (slet* ((x 3) (y 4))
             (some-macro)))))))

This produces
NIL
NIL
3
4
when compiled.

> 
> :)
> 

Thanks for the reply... ;)


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Kaz Kylheku
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <1149541295.216323.104000@f6g2000cwb.googlegroups.com>
Pascal Costanza wrote:
>             ((%aliases ',(append aliases
>                                  (cadr (macroexpand '%aliases env)))))

You know, I suspect that the culprit is this, somehow. The environment
is perhaps not being processed properly here.

For MACROLET, the CLHS says:

  "In addition to macro definitions in the global environment, any
  local macro definitions established within env by macrolet or
  symbol-macrolet are considered."

But is the %ALIASES symbol-macrolet required to be established in this
env? This is perhaps the problem.

On the other hand, the MACROEXPAND must be producing a cons, otherwise
CADR would blow up, right. Hmm! Ah, but you set up a global symbol
macro for %ALIASES. So if the local symbol macro isn't found in ENV,
MACROEXPAND will produce the global one.

Add, to your test case's local macro, a PRINT call that just dumps
%ALIASES. I bet you will see the global one, and not the local one.

In fact, change the DEFINE-SYMBOL-MACRO for %ALIASES so that it expands
to something other than NIL, like say ((FOO BAR)). That way you can
recognize the global tail portion.
From: Pascal Costanza
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <4ejmloF1evgbgU1@individual.net>
Kaz Kylheku wrote:
> Pascal Costanza wrote:
>>             ((%aliases ',(append aliases
>>                                  (cadr (macroexpand '%aliases env)))))
> 
> You know, I suspect that the culprit is this, somehow. The environment
> is perhaps not being processed properly here.
> 
> For MACROLET, the CLHS says:
> 
>   "In addition to macro definitions in the global environment, any
>   local macro definitions established within env by macrolet or
>   symbol-macrolet are considered."
> 
> But is the %ALIASES symbol-macrolet required to be established in this
> env? This is perhaps the problem.

I guess so, but my understanding of the spec is that it should be added 
to the environment object. (The wording "affect" is somewhat imprecise, 
but what else should it mean?)

> On the other hand, the MACROEXPAND must be producing a cons, otherwise
> CADR would blow up, right. Hmm! Ah, but you set up a global symbol
> macro for %ALIASES. So if the local symbol macro isn't found in ENV,
> MACROEXPAND will produce the global one.
> 
> Add, to your test case's local macro, a PRINT call that just dumps
> %ALIASES. I bet you will see the global one, and not the local one.

Right.

> In fact, change the DEFINE-SYMBOL-MACRO for %ALIASES so that it expands
> to something other than NIL, like say ((FOO BAR)). That way you can
> recognize the global tail portion.

Right. Your guesses are correct.

But here is something else that I have discovered: The following program 
cannot be compiled in Allegro (unless you have loaded the .lisp file 
beforehand).

(define-symbol-macro %test 42)

(defmacro m () %test)

(defun test () (m))



Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Kaz Kylheku
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <1149544514.585924.159150@h76g2000cwa.googlegroups.com>
Pascal Costanza wrote:
> But here is something else that I have discovered: The following program
> cannot be compiled in Allegro (unless you have loaded the .lisp file
> beforehand).
>
> (define-symbol-macro %test 42)
>
> (defmacro m () %test)
>
> (defun test () (m))

Strange. Is it because the symbol macro isn't being defined in the
compiler? 

Will it work if you put the familiar EVAL-WHEN around it?
From: Harald Hanche-Olsen
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <pcoverfmfj6.fsf@shuttle.math.ntnu.no>
+ Pascal Costanza <··@p-cos.net>:

| But here is something else that I have discovered: The following
| program cannot be compiled in Allegro (unless you have loaded the
| .lisp file beforehand).
|
| (define-symbol-macro %test 42)
|
| (defmacro m () %test)
|
| (defun test () (m))

Perhaps because define-symbol-macro is not among the macros listed at
the bottom of page 3.2.3.1.1 in the Hyperspec.  Meaning you may have
to wrap it in an EVAL-WHEN.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Duane Rettig
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <o08xob5jnx.fsf@franz.com>
Harald Hanche-Olsen <······@math.ntnu.no> writes:

> + Pascal Costanza <··@p-cos.net>:
>
> | But here is something else that I have discovered: The following
> | program cannot be compiled in Allegro (unless you have loaded the
> | .lisp file beforehand).
> |
> | (define-symbol-macro %test 42)
> |
> | (defmacro m () %test)
> |
> | (defun test () (m))
>
> Perhaps because define-symbol-macro is not among the macros listed at
> the bottom of page 3.2.3.1.1 in the Hyperspec.  Meaning you may have
> to wrap it in an EVAL-WHEN.

It would have been a nice excuse for us to make, but that doesn't
explain why a file with:

=====
(define-symbol-macro %test 42)

(defmacro m () '%test)

(defun test () (m))
=====

does work as expected.

No, we view the ommision in 3.2.3.1.1 as just that; an omission, due
to the relatively late addition of define-symbol-macro (in fact, take
a look at its definition in CLtL2)...

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Pascal Costanza
Subject: Re: Closer to macro hygiene
Date: 
Message-ID: <4ejofdF1ev3vgU1@individual.net>
Harald Hanche-Olsen wrote:
> + Pascal Costanza <··@p-cos.net>:
> 
> | But here is something else that I have discovered: The following
> | program cannot be compiled in Allegro (unless you have loaded the
> | .lisp file beforehand).
> |
> | (define-symbol-macro %test 42)
> |
> | (defmacro m () %test)
> |
> | (defun test () (m))
> 
> Perhaps because define-symbol-macro is not among the macros listed at
> the bottom of page 3.2.3.1.1 in the Hyperspec.  Meaning you may have
> to wrap it in an EVAL-WHEN.

That's weird, but you are indeed right. (And the code works when wrapped 
with the right eval-when magic.)


Pascal

-- 
3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/