From: ········@gmail.com
Subject: macro evaluation
Date: 
Message-ID: <1118194618.713902.263320@g49g2000cwa.googlegroups.com>
So here's my problem : I have a macro mac1 such that the expansion of
(mac1 x) depends on the value of some special variable *v*.  I also
have another macro mac2.  I would like mac2 to be something

(defmacro mac2 (val &rest body)
  `(progn
      (setf *v* ,val)
      ,@body
      (setf *v* nil)))

In other words, I want *v* to equal val while the body is being
evaluated.

Now I have a file foo.lisp containing

(mac2 42 (mac1 (bar)))

Now the problem I get is when I compile foo.lisp, *v* is not set to 42
when (mac1 (bar)) is being expanded - it is nil.  How would I get the
desired behaviour to happen?

- Bhaskara

From: Eric Lavigne
Subject: Re: macro evaluation
Date: 
Message-ID: <1118197211.144159.145830@g47g2000cwa.googlegroups.com>
>So here's my problem : I have a macro mac1 such that the expansion of
>(mac1 x) depends on the value of some special variable *v*.  I also
>have another macro mac2.  I would like mac2 to be something

>(defmacro mac2 (val &rest body)
>  `(progn
>      (setf *v* ,val)
>      ,@body
>      (setf *v* nil)))

>In other words, I want *v* to equal val while the body is being
>evaluated.

>Now I have a file foo.lisp containing

>(mac2 42 (mac1 (bar)))

>Now the problem I get is when I compile foo.lisp, *v* is not set to 42
>when (mac1 (bar)) is being expanded - it is nil.  How would I get the
>desired behaviour to happen?

>- Bhaskara

Macros are still a bit of a mystery to me, but here's my two cents.

(defparameter *v* 77)

(defmacro mac2 (val &body body)
  `(let ((*v* ,val))
      ,@body))

(defmacro mac1-wrong ()
  `(format t "~a" ,*v*))

(defmacro mac1-right ()
  '(format t "~a" *v*))

(let ((*v* 42)) (mac1-wrong)) --> 77
(mac2 42 (mac1-wrong))  --> 77
(mac2 42 (mac2-right)) --> 42

This seems to be a problem with mac1, not with mac2. Show us what your
mac2 looks like and let's try to fix it so that it is able to capture
symbols from its environment.
From: Eric Lavigne
Subject: Re: macro evaluation
Date: 
Message-ID: <1118197676.922229.309330@g49g2000cwa.googlegroups.com>
(let ((*v* 42)) (mac1-wrong)) --> 77
(mac2 42 (mac1-wrong))  --> 77
(mac2 42 (mac2-right)) --> 42

>This seems to be a problem with mac1, not with mac2. Show us what your
>mac2 looks like and let's try to fix it so that it is able to capture
>symbols from its environment.

I meant show us mac1 ^^ Clearly mac1 was designed to capture the
variable *v*, but as it works now mac1 sees only the original value of
the variable, rather than the local environment. This is a bug in mac1,
not a bug in mac2.
From: Pascal Bourguignon
Subject: Re: macro evaluation
Date: 
Message-ID: <87d5qx4m4o.fsf@thalassa.informatimago.com>
········@gmail.com writes:

> So here's my problem : I have a macro mac1 such that the expansion of
> (mac1 x) depends on the value of some special variable *v*.  

This formulation is a little ambiguous.  Does mac1 need *v* at
macroexpansion time or does it need at runtime?


> I also
> have another macro mac2.  I would like mac2 to be something
>
> (defmacro mac2 (val &rest body)
>   `(progn
>       (setf *v* ,val)
>       ,@body
>       (setf *v* nil)))
>
> In other words, I want *v* to equal val while the body is being
> evaluated.
>
> Now I have a file foo.lisp containing
>
> (mac2 42 (mac1 (bar)))
>
> Now the problem I get is when I compile foo.lisp, *v* is not set to 42
> when (mac1 (bar)) is being expanded - it is nil.  How would I get the
> desired behaviour to happen?


If mac1 needs *v* at runtime:

(defmacro mac1 (&body body)
   `(progn (print *v*) ,@body))

(defmacro mac2 (val &rest body)
   `(let ((*v* ,val))
       ,@body))
or:

(defvar *v*)
(defmacro mac2 (val &rest body)
   `(unwind-protect
        (progn (setf *v* ,val) ,@body)
        (setf *v* nil)))


then it will work as you want:


[43]> (ext:expand-form `(mac2 42 (mac1 (bar))))
(UNWIND-PROTECT
     (PROGN (SETQ *V* 42) (PROGN (PRINT *V*) (BAR))) 
     (SETQ *V* NIL)) ;
T



If mac1 needs *v* at macroexpansion time:

(eval-when (:compile-toplevel) (defvar *v*))

(defmacro mac1 (&body body)
    (if (eq *v* :debug)
      `(unwind-protect
            (progn (format *trace-output* "Before executing ~S~%" ',body)
                   ,@body)
          (format *trace-output* "After executing ~S~%" ',body))
      `(progn ,@body)))

Then mac2 must modify *v* at macroexpansion time too:

(defmacro mac2 (val &body body)
    (setf *v* val)
    `(progn ,@body))

But note that macroexpansion of mac1 will occur after mac2 terminates,
so you don't want to reset *v* to nil here.
    

[38]> (ext:expand-form `(mac2 42 (mac1 (bar))))
(BAR) ;
T
[39]> (ext:expand-form `(mac2 :debug (mac1 (bar))))
(UNWIND-PROTECT
 (PROGN (FORMAT *TRACE-OUTPUT* "Before executing ~S~%" '((BAR))) (BAR))
 (FORMAT *TRACE-OUTPUT* "After executing ~S~%" '((BAR)))) ;
T


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

In a World without Walls and Fences, 
who needs Windows and Gates?
From: Kaz Kylheku
Subject: Re: macro evaluation
Date: 
Message-ID: <1118246698.468257.196050@g49g2000cwa.googlegroups.com>
Pascal Bourguignon wrote:
> ········@gmail.com writes:
>
> > So here's my problem : I have a macro mac1 such that the expansion of
> > (mac1 x) depends on the value of some special variable *v*.
>
> This formulation is a little ambiguous.  Does mac1 need *v* at
> macroexpansion time or does it need at runtime?

You are right. The ambiguity in bhashara's sentence is that
``expansion'' has two meanings: expansion process and expansion result.
I think it's the former interpretation, because then he or she wouldn't
be having all these difficulties not seeing the result of the SETF in
the expected context.
From: ········@gmail.com
Subject: Re: macro evaluation
Date: 
Message-ID: <1118252969.173990.165610@g43g2000cwa.googlegroups.com>
Thanks to everyone for the suggestions.  mac1 looks at *v* at
macroexpansion time - the second case in the parent email.  I had
originally tried something like the solution there, except that I was
resetting *v* :
(defmacro mac2 (val &body body)
    (setf *v* val)
    `(progn ,@body)
    (setf *v* nil))

and assume foo.lisp contains
(mac2 42 (mac1 (bar)))

This actually works ok when loading foo.lisp, but as Pascal pointed
out, when compiling, *v* is nil by the time the mac1 call is expanded.

So I followed his suggestion and removed the (setf *v* nil) and it
works correctly in a simple test case.  I just want to be sure this
will always work, under any compiler.  Suppose the file foo.lisp
contains

(mac2 42 (mac1 (bar)))
(mac2 24 (mac1 (baz)))

Of course, this means I want *v* to equal 42 when (mac1 (bar)) is
expanded and 24 when (mac1 (baz)) is expanded.  Assuming each form is
completely expanded before moving to the next one, this will work.
What I'm worried about is the following sequence of events:
1. *v* is set to 42 and the first mac2 call is expanded into (mac1
(bar))
2. *v* is set to 24 and the second mac2 call is expanded into (mac1
(baz))
3. (mac1 (bar)) is now expanded, but *v* equals 24.

Is there anything in the lisp spec about order of expansion that
guarantees that this won't happen?
From: ···········@gmail.com
Subject: Re: macro evaluation
Date: 
Message-ID: <1118367074.864451.20690@f14g2000cwb.googlegroups.com>
I don't think so - there's no way you can ensure that one thing is
expanded before another.

········@gmail.com wrote:
> Thanks to everyone for the suggestions.  mac1 looks at *v* at
> macroexpansion time - the second case in the parent email.  I had
> originally tried something like the solution there, except that I was
> resetting *v* :
> (defmacro mac2 (val &body body)
>     (setf *v* val)
>     `(progn ,@body)
>     (setf *v* nil))
>
> and assume foo.lisp contains
> (mac2 42 (mac1 (bar)))
>
> This actually works ok when loading foo.lisp, but as Pascal pointed
> out, when compiling, *v* is nil by the time the mac1 call is expanded.
>
> So I followed his suggestion and removed the (setf *v* nil) and it
> works correctly in a simple test case.  I just want to be sure this
> will always work, under any compiler.  Suppose the file foo.lisp
> contains
>
> (mac2 42 (mac1 (bar)))
> (mac2 24 (mac1 (baz)))
>
> Of course, this means I want *v* to equal 42 when (mac1 (bar)) is
> expanded and 24 when (mac1 (baz)) is expanded.  Assuming each form is
> completely expanded before moving to the next one, this will work.
> What I'm worried about is the following sequence of events:
> 1. *v* is set to 42 and the first mac2 call is expanded into (mac1
> (bar))
> 2. *v* is set to 24 and the second mac2 call is expanded into (mac1
> (baz))
> 3. (mac1 (bar)) is now expanded, but *v* equals 24.
>
> Is there anything in the lisp spec about order of expansion that
> guarantees that this won't happen?
From: Paul F. Dietz
Subject: Re: macro evaluation
Date: 
Message-ID: <xqmdnd3UMOJMczXfRVn-hA@dls.net>
···········@gmail.com wrote:

> I don't think so - there's no way you can ensure that one thing is
> expanded before another.


Let me add that you really *don't* want to use special variables
to communicate between macros.  Instead, use &environment arguments,
and communicate through them using auxiliary macrolets.  This gives
you top-down flow of data, which is often what you want.

	Paul
From: ········@gmail.com
Subject: Re: macro evaluation
Date: 
Message-ID: <1118426381.984771.10320@g44g2000cwa.googlegroups.com>
Paul F. Dietz wrote:
> ···········@gmail.com wrote:
>
> > I don't think so - there's no way you can ensure that one thing is
> > expanded before another.
>
>
> Let me add that you really *don't* want to use special variables
> to communicate between macros.  Instead, use &environment arguments,
> and communicate through them using auxiliary macrolets.  This gives
> you top-down flow of data, which is often what you want.
>
> 	Paul

Hmm, I'm not familiar with these 'environment arguments' of which you
speak, and CLHS is not helping.  Would you mind giving or pointing me
to an explanation of how to use them to accomplish communication?
From: Paul F. Dietz
Subject: Re: macro evaluation
Date: 
Message-ID: <JqqdnR0z-PMqUjffRVn-sw@dls.net>
········@gmail.com wrote:

> Hmm, I'm not familiar with these 'environment arguments' of which you
> speak, and CLHS is not helping.  Would you mind giving or pointing me
> to an explanation of how to use them to accomplish communication?

See the definition of macro lambda lists, DEFMACRO, and MACROLET.
When you define a macro, you can specify an &environment argument:

   (macrolet ((foo (x y &environment env)))
     ...)

This argument can be passed to MACROEXPAND and MACROEXPAND-1 and
causes those functions to 'see' any MACROLET (and global macro
definitions) surrounding the lexical location where the (foo ...)
form being expanded is located.

The trick here is to construct auxiliary macrolets whose presence
and/or value can be probed by calling MACROEXPAND or MACROEXPAND-1
wih the env argument.  This works regardless of the macro-expansion
order or multiplicity, or whether it occurs before or during evaluation.

Example:

(macrolet ((%v () 'x))
    ...
    (macrolet ((%foo (y &environment env)
                  (if (eql (macroexpand '(%v) env) 'x)
                      `(car ,y)
                      `(cdr ,y))))
        (values
           (%foo '(a b))
           (macrolet ((%v () nil))
              (%foo '(a b)))
           (%foo '(a b))
      )))
==>
A
(B)
A


As an side...

Environment objects also contain information about declarations,
but many of these cannot be accessed in a standard way.  A proposed
means to do so didn't make it into the final standard.  Franz's
Allegro CL has put in another way to do this in ACL 7.0.

	Paul
From: Duane Rettig
Subject: Re: macro evaluation
Date: 
Message-ID: <4slzorcsu.fsf@franz.com>
"Paul F. Dietz" <·····@dls.net> writes:

> As an side...
> 
> Environment objects also contain information about declarations,
> but many of these cannot be accessed in a standard way.  A proposed
> means to do so didn't make it into the final standard.  Franz's
> Allegro CL has put in another way to do this in ACL 7.0.

Yes, it's slightly different than the way CLtL2 specified it (which
had some unresolved problems as it was specified, and thus had to
have some changes).  But I am actually pleased at how close we were
able to come to the same interface, for the most part, as is given in
CLtL2.  Anyone who wants to know more can sign up for the tutorial I'm
giving at the ILC conference a week from Sunday.

http://international-lisp-conference.org/

-- 
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: ········@gmail.com
Subject: Re: macro evaluation
Date: 
Message-ID: <1118520419.150581.182730@g44g2000cwa.googlegroups.com>
It works... cool!

Paul F. Dietz wrote:
> ········@gmail.com wrote:
>
> > Hmm, I'm not familiar with these 'environment arguments' of which you
> > speak, and CLHS is not helping.  Would you mind giving or pointing me
> > to an explanation of how to use them to accomplish communication?
>
> See the definition of macro lambda lists, DEFMACRO, and MACROLET.
> When you define a macro, you can specify an &environment argument:
>
>    (macrolet ((foo (x y &environment env)))
>      ...)
>
> This argument can be passed to MACROEXPAND and MACROEXPAND-1 and
> causes those functions to 'see' any MACROLET (and global macro
> definitions) surrounding the lexical location where the (foo ...)
> form being expanded is located.
>
> The trick here is to construct auxiliary macrolets whose presence
> and/or value can be probed by calling MACROEXPAND or MACROEXPAND-1
> wih the env argument.  This works regardless of the macro-expansion
> order or multiplicity, or whether it occurs before or during evaluation.
>
> Example:
>
> (macrolet ((%v () 'x))
>     ...
>     (macrolet ((%foo (y &environment env)
>                   (if (eql (macroexpand '(%v) env) 'x)
>                       `(car ,y)
>                       `(cdr ,y))))
>         (values
>            (%foo '(a b))
>            (macrolet ((%v () nil))
>               (%foo '(a b)))
>            (%foo '(a b))
>       )))
> ==>
> A
> (B)
> A
>
>
> As an side...
>
> Environment objects also contain information about declarations,
> but many of these cannot be accessed in a standard way.  A proposed
> means to do so didn't make it into the final standard.  Franz's
> Allegro CL has put in another way to do this in ACL 7.0.
> 
> 	Paul
From: Kalle Olavi Niemitalo
Subject: Re: macro evaluation
Date: 
Message-ID: <87acm1b7zi.fsf@Astalo.kon.iki.fi>
Pascal Bourguignon <···@informatimago.com> writes:

> Then mac2 must modify *v* at macroexpansion time too:
>
> (defmacro mac2 (val &body body)
>     (setf *v* val)
>     `(progn ,@body))

One could also do this:

  (defmacro mac2 (val &body body &environment env)
    (let ((*v* val))
      `(progn ,@(loop for form in body
                      collect (macroexpand form env)))))

However, this will only work if the body directly contains a mac1
form, not if mac1 is used in a subform.  To support the latter,
you'd need a code walker (like EXT:EXPAND-FORM of CLISP) or
COMPILER-LET, which was removed from the standard but may be
available in some implementations.

If you are able to modify MAC1, the most reliable solution is to
make MAC2 define a local macro, rather than bind a special
variable.  For example:

  (defmacro mac1 (&body body)
    `(progn ,@body))

  (defmacro mac2 (val &body outer-body)
    `(macrolet ((mac1 (&body body)
                  ,(if (eq val :debug)
                     '`(unwind-protect
                           (progn (format *trace-output*
                                          "Before executing ~S~%" ',body)
                                  ,@body)
                         (format *trace-output* "After executing ~S~%" ',body))
                     '`(progn ,@body))))
       ,@outer-body))

Then there will be no doubt on which uses of MAC1 are affected.
The same can also be done with an auxiliary macro:

  (define-symbol-macro .mac1-option. nil)

  (defmacro mac1 (&body body &environment env)
    (if (eq (let ((*macroexpand-hook* #'funcall))
              (macroexpand-1 '.mac1-option. env))
            :debug)
      `(unwind-protect
            (progn (format *trace-output* "Before executing ~S~%" ',body)
                   ,@body)
          (format *trace-output* "After executing ~S~%" ',body))
      `(progn ,@body)))

  (defmacro mac2 (val &body body)
    `(symbol-macrolet ((.mac1-option. ,val))
       ,@body))

.MAC1-OPTION. could have been a regular macro, but I used a symbol
macro because that is simpler in a way.
From: Thomas A. Russ
Subject: Re: macro evaluation
Date: 
Message-ID: <ymi1x7auo9o.fsf@sevak.isi.edu>
········@gmail.com writes:

> 
> So here's my problem : I have a macro mac1 such that the expansion of
> (mac1 x) depends on the value of some special variable *v*.  I also
> have another macro mac2.  I would like mac2 to be something

OK, a general comment.  Rather than setting and then restoring? a
special variable value, you should just use LET to bind it.

Bindings that need to happen at macroexpand time need to be outside the
returned expansion.  The code below will only set *V* during the
evaluation of the body, but not during its macroexpansion.

> (defmacro mac2 (val &rest body)
>   `(progn
>       (setf *v* ,val)
>       ,@body
>       (setf *v* nil)))
> 
> In other words, I want *v* to equal val while the body is being
> evaluated.

That is what happens, but it is during EVALUATION, not MACRO-EXPANSION.


> Now the problem I get is when I compile foo.lisp, *v* is not set to 42
> when (mac1 (bar)) is being expanded - it is nil.  How would I get the
> desired behaviour to happen?

What is it you are really trying to accomplish?  What is your larger
goal?  There may be a better or simpler way of doing that instead.


-- 
Thomas A. Russ,  USC/Information Sciences Institute