I have a macro that expands in one of two ways. I would like for the
choice of expansions to be made according to the lexical context in which
the macro finds itself. In other words, I would like the following
behavior:
(with-context-1 ... (my-macro) ...) ==> (... expansion-1 ...)
(with-context-2 ... (my-macro) ...) ==> (... expansion-2 ...)
Is there any way to do that without a full code walker?
Thanks,
E.
In article
<···········································@k-137-79-50-101.jpl.nasa.gov>,
··························@jpl.nasa.gov (Erann Gat) wrote:
> I have a macro that expands in one of two ways. I would like for the
> choice of expansions to be made according to the lexical context in which
> the macro finds itself. In other words, I would like the following
> behavior:
>
> (with-context-1 ... (my-macro) ...) ==> (... expansion-1 ...)
> (with-context-2 ... (my-macro) ...) ==> (... expansion-2 ...)
>
> Is there any way to do that without a full code walker?
Never mind, I figured it out.
(defmacro with-context (context &body body)
(let ( (*context* context) )
`(funcall ',(compile nil (lambda () ,@body)))))
(The compiler *is* a code-walker. Duh!)
I wonder, can you do that in Scheme? :-)
E.
Erann Gat wrote:
>>I have a macro that expands in one of two ways. I would like for the
>>choice of expansions to be made according to the lexical context in which
>>the macro finds itself. In other words, I would like the following
>>behavior:
>>
>>(with-context-1 ... (my-macro) ...) ==> (... expansion-1 ...)
>>(with-context-2 ... (my-macro) ...) ==> (... expansion-2 ...)
>>
>>Is there any way to do that without a full code walker?
>
>
> Never mind, I figured it out.
>
> (defmacro with-context (context &body body)
> (let ( (*context* context) )
> `(funcall ',(compile nil (lambda () ,@body)))))
>
> (The compiler *is* a code-walker. Duh!)
>
> I wonder, can you do that in Scheme? :-)
This isn't how I would do it.
Instead, I'd have WITH-CONTEXT-1 and WITH-CONTEXT-2 expand into
signalling macrolets. Your macro could detect the presence of this
signalling macrolet by means of an &environment parameter:
(with-context-1 ...) ==>
(macrolet ((context-indicator () 'context-1))
...)
(with-context-2 ...) ==>
(macrolet ((context-indicator () 'context-2))
...)
(defmacro my-macro (&environment env)
(ecase (macroexpand '(context-indicator) env)
(context-1 ...)
(context-2 ...)))
Paul
In article <······················@dls.net>, "Paul F. Dietz"
<·····@dls.net> wrote:
> Erann Gat wrote:
>
> >>I have a macro that expands in one of two ways. I would like for the
> >>choice of expansions to be made according to the lexical context in which
> >>the macro finds itself. In other words, I would like the following
> >>behavior:
> >>
> >>(with-context-1 ... (my-macro) ...) ==> (... expansion-1 ...)
> >>(with-context-2 ... (my-macro) ...) ==> (... expansion-2 ...)
> >>
> >>Is there any way to do that without a full code walker?
> >
> >
> > Never mind, I figured it out.
> >
> > (defmacro with-context (context &body body)
> > (let ( (*context* context) )
> > `(funcall ',(compile nil (lambda () ,@body)))))
> >
> > (The compiler *is* a code-walker. Duh!)
> >
> > I wonder, can you do that in Scheme? :-)
>
>
> This isn't how I would do it.
>
> Instead, I'd have WITH-CONTEXT-1 and WITH-CONTEXT-2 expand into
> signalling macrolets. Your macro could detect the presence of this
> signalling macrolet by means of an &environment parameter:
>
> (with-context-1 ...) ==>
> (macrolet ((context-indicator () 'context-1))
> ...)
> (with-context-2 ...) ==>
> (macrolet ((context-indicator () 'context-2))
> ...)
>
> (defmacro my-macro (&environment env)
> (ecase (macroexpand '(context-indicator) env)
> (context-1 ...)
> (context-2 ...)))
So that's what those &environment thingies are for! I've been wondering
about that for years. :-)
Thanks!
E.
I want to endorse Paul's wisdon here. Use of macrolets is the right thing, since
macrolets belong to the lexical environment. Depending on a special variable to
carry contextual information to macros makes aassumptions about how the compiler
happens to work as a code walker, and I believe it is possible to write a code
that works in a way that is not congruent with dynamic state.
In article <·······················@newssvr13.news.prodigy.com>, "Steven
M. Haflich" <·················@alum.mit.edu> wrote:
> I want to endorse Paul's wisdon here. Use of macrolets is the right
thing, since
> macrolets belong to the lexical environment. Depending on a special
variable to
> carry contextual information to macros makes aassumptions about how the
compiler
> happens to work as a code walker, and I believe it is possible to write a code
> that works in a way that is not congruent with dynamic state.
Yes, that's clear to me now.
Two things I am still curious about.
1. What else is &environment useful for?
2. Is this programming technique writte down anywhere? "On Lisp", which
everyone seems to consider the canonical reference on advanced macros,
says nothing about &environment.
E.
Erann Gat wrote:
> 1. What else is &environment useful for?
Standardly, not much else (CONSTANTP, maybe?)
This is an area ripe for extension. It would be very useful for
(for example) making declaration information available in macros or
compiler macros. As Duane recently said, this kind of thing was not
added to the standard because it wasn't fully baked.
Paul
··························@jpl.nasa.gov (Erann Gat) writes:
> 1. What else is &environment useful for?
You sometimes have to pass it on, for instance in
MAKE-LOAD-FORM-SAVING-SLOTS. And for code-walking, of course, only
that accessing and manipulating the environment objects isn't
portable, unfortunately.
Regards,
--
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."
PGP key ID 0x0655CFA0
··························@jpl.nasa.gov (Erann Gat) writes:
> In article <·······················@newssvr13.news.prodigy.com>, "Steven
> M. Haflich" <·················@alum.mit.edu> wrote:
>
> > I want to endorse Paul's wisdon here. Use of macrolets is the
> > right thing, since macrolets belong to the lexical environment.
> > Depending on a special variable to carry contextual information to
> > macros makes aassumptions about how the compiler happens to work
> > as a code walker, and I believe it is possible to write a code
> > that works in a way that is not congruent with dynamic state.
>
> Yes, that's clear to me now.
>
> Two things I am still curious about.
>
> 1. What else is &environment useful for?
This is not really an answer to your question but since I happened to
have done the work tracking it down, here's a list of (I think) all
the functions in the standard that take an environment object as an
argument:
Accessor COMPILER-MACRO-FUNCTION
Accessor MACRO-FUNCTION
Function CONSTANTP
Function GET-SETF-EXPANSION
Function MACROEXPAND
Function MACROEXPAND-1
Function MAKE-LOAD-FORM-SAVING-SLOTS
Function SUBTYPEP
Function TYPEP
Function UPGRADED-ARRAY-ELEMENT-TYPE
Function UPGRADED-COMPLEX-PART-TYPE
Standard Generic Function MAKE-LOAD-FORM
There are also some X3J13 issues in the HyperSpec that talk about
environments some.
-Peter
--
Peter Seibel ·····@javamonkey.com
Lisp is the red pill. -- John Fraser, comp.lang.lisp
In article <·······················@newssvr13.news.prodigy.com>,
Steven M. Haflich <·················@alum.mit.edu> wrote:
>I want to endorse Paul's wisdon here. Use of macrolets is the right thing, since
>macrolets belong to the lexical environment.
BTW, this is what the old COMPILER-LET was for, but we got rid of it when
we realized that this MACROLET trick could be used to the same end.
--
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
··························@jpl.nasa.gov (Erann Gat) wrote in message news:<···········································@k-137-79-50-101.jpl.nasa.gov>...
> In article
> <···········································@k-137-79-50-101.jpl.nasa.gov>,
> ··························@jpl.nasa.gov (Erann Gat) wrote:
>
> > I have a macro that expands in one of two ways. I would like for the
> > choice of expansions to be made according to the lexical context in which
> > the macro finds itself. In other words, I would like the following
> > behavior:
> >
> > (with-context-1 ... (my-macro) ...) ==> (... expansion-1 ...)
> > (with-context-2 ... (my-macro) ...) ==> (... expansion-2 ...)
> >
> > Is there any way to do that without a full code walker?
>
> Never mind, I figured it out.
>
> (defmacro with-context (context &body body)
> (let ( (*context* context) )
> `(funcall ',(compile nil (lambda () ,@body)))))
I think you have two commas out to one backquote in. This is probably
right:
`(funcall ,(compile nil `(lambda () ,@body)))
where we are taking advantage of the ability of COMPILE to take a
lambda expression in the place of a closure.
The problem with this approach is that the BODY forms are not
evaluated in the surrounding lexical context, and so the body cannot
refer to surrounding lexical variables.
Yes you have a lambda there, but it won't capture anything, because
after my correction is applied, it becomes obvious that it's just a
dead list that only becomes live code in the bowels of the compiler
subroutine. COMPILE isn't much different from EVAL in this regard.
> (The compiler *is* a code-walker. Duh!)
My first thought was that MY-MACRO should be a macrolet, so that
(with-context-1 ...(my-macro) ...)
expands into something like
(macrolet ((my-macro () ...))
... (my-macro) ...)
Of course, the definition of MY-MACRO varies among the different
WITH-CONTEXT-* forms, but if the definitions are similar, the
expanders for these macros can share a lot of common code.
Local macros are your first resource when you suspect you need a code
walker.
In article <····························@posting.google.com>,
···@ashi.footprints.net (Kaz Kylheku) wrote:
> ··························@jpl.nasa.gov (Erann Gat) wrote in message
news:<···········································@k-137-79-50-101.jpl.nasa.gov>...
> > In article
> > <···········································@k-137-79-50-101.jpl.nasa.gov>,
> > ··························@jpl.nasa.gov (Erann Gat) wrote:
> >
> > > I have a macro that expands in one of two ways. I would like for the
> > > choice of expansions to be made according to the lexical context in which
> > > the macro finds itself. In other words, I would like the following
> > > behavior:
> > >
> > > (with-context-1 ... (my-macro) ...) ==> (... expansion-1 ...)
> > > (with-context-2 ... (my-macro) ...) ==> (... expansion-2 ...)
> > >
> > > Is there any way to do that without a full code walker?
> >
> > Never mind, I figured it out.
> >
> > (defmacro with-context (context &body body)
> > (let ( (*context* context) )
> > `(funcall ',(compile nil (lambda () ,@body)))))
>
> I think you have two commas out to one backquote in. This is probably
> right:
>
> `(funcall ,(compile nil `(lambda () ,@body)))
Yep. I'm not sure how that other version got into the post. It doesn't
even compile.
> where we are taking advantage of the ability of COMPILE to take a
> lambda expression in the place of a closure.
>
> The problem with this approach is that the BODY forms are not
> evaluated in the surrounding lexical context, and so the body cannot
> refer to surrounding lexical variables.
Hm, good point.
> Local macros are your first resource when you suspect you need a code
> walker.
A good rule to remember. Thanks.
E.