I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
analogy) somewhat like FLET in the sense that the local macros may not
call one another. But what if the desired behavior were more like
LABELS, where not only could they call one another, but you could have
recursive macro calls as well, for instance.
Is there some other special form for doing that? Or can it be achieved
at all?
Thank you.
Hi,
On 13 Apr., 12:38, ···········@gmail.com wrote:
> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
> analogy) somewhat like FLET in the sense that the local macros may not
> call one another. But what if the desired behavior were more like
> LABELS, where not only could they call one another, but you could have
> recursive macro calls as well, for instance.
>
> Is there some other special form for doing that? Or can it be achieved
> at all?
I'm not sure I mean the same by `calling' in this case as PG does, but
if I do, it wouldn't make any sense at all, because macros are called
at compile-time, at this point they have to have been compiled
already.
Note that the following does work, because the local macro FOO expands
to (rather than calling) itself, so it's called from within the body
of the macrolet form, not from within the definition of FOO:
CL-USER> (macrolet ((foo (n)
(if (plusp n)
`(progn
(foo ,(1- n))
(print ,n)
(values))
nil)))
(foo 3))
1
2
3
; No value
Hope this helps,
~ Matthias
rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
rr> analogy) somewhat like FLET in the sense that the local macros may not
rr> call one another. But what if the desired behavior were more like
rr> LABELS, where not only could they call one another, but you could have
rr> recursive macro calls as well, for instance.
either you're missing the way how macros work -- they do not _call_ each
other, but just code generated by one macro might contain references to
another one, so it just needs one more round of macroexpansion.
or you're doing something impressive like macro-defining-macros, then we'd
appreciated if you share this stuff with us!
for example,
(macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
(macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
(repeat-3-times (print "recursive macros are mind-boggling"))))
this won't work in single macrolet -- it will complain about
n-times-repeater being not defined.
i'm afraid i'm not able to invent anything that can't be handled with nested
macrolets..
On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
wrote:
> rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
> rr> analogy) somewhat like FLET in the sense that the local macros may not
> rr> call one another. But what if the desired behavior were more like
> rr> LABELS, where not only could they call one another, but you could have
> rr> recursive macro calls as well, for instance.
>
> either you're missing the way how macros work -- they do not _call_ each
> other, but just code generated by one macro might contain references to
> another one, so it just needs one more round of macroexpansion.
> or you're doing something impressive like macro-defining-macros, then we'd
> appreciated if you share this stuff with us!
>
> for example,
>
> (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
> (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
> (repeat-3-times (print "recursive macros are mind-boggling"))))
>
> this won't work in single macrolet -- it will complain about
> n-times-repeater being not defined.
> i'm afraid i'm not able to invent anything that can't be handled with nested
> macrolets..
Well, to tell you the truth, Alex, concerning the "calling" part, I
was merely repeating Graham's words (quote):
"(macrolet ((symbol parameters . body)*)
Special Operator
declaration* expression*)
Evaluates its body with each symbol defined locally to be the
corresponding
macro. The expansion functions are defined in the lexical
environment where
the macrolet expression occurs. Like f l e t , the local macros
may not call
one another."
As you can see, he explicitly says " ... the local macros may not call
one another." So I guess he's got this calling business all wrong,
perhaps ;)
I gather, from what you're saying, that the only way to do what I was
asking is through the use of nested MACROLETs. Am I correct?
Thanks.
···········@gmail.com writes:
> On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
> wrote:
> > rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
> > rr> analogy) somewhat like FLET in the sense that the local macros may not
> > rr> call one another. But what if the desired behavior were more like
> > rr> LABELS, where not only could they call one another, but you could have
> > rr> recursive macro calls as well, for instance.
> >
> > either you're missing the way how macros work -- they do not _call_ each
> > other, but just code generated by one macro might contain references to
> > another one, so it just needs one more round of macroexpansion.
> > or you're doing something impressive like macro-defining-macros, then we'd
> > appreciated if you share this stuff with us!
> >
> > for example,
> >
> > (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
> > (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
> > (repeat-3-times (print "recursive macros are mind-boggling"))))
> >
> > this won't work in single macrolet -- it will complain about
> > n-times-repeater being not defined.
> > i'm afraid i'm not able to invent anything that can't be handled with nested
> > macrolets..
>
> Well, to tell you the truth, Alex, concerning the "calling" part, I
> was merely repeating Graham's words (quote):
>
> "(macrolet ((symbol parameters . body)*)
> Special Operator
> declaration* expression*)
> Evaluates its body with each symbol defined locally to be the
> corresponding
> macro. The expansion functions are defined in the lexical
> environment where
> the macrolet expression occurs. Like f l e t , the local macros
> may not call
> one another."
>
> As you can see, he explicitly says " ... the local macros may not call
> one another." So I guess he's got this calling business all wrong,
> perhaps ;)
>
> I gather, from what you're saying, that the only way to do what I was
> asking is through the use of nested MACROLETs. Am I correct?
>
I was puzzled by the idea that macrolet works like flet,
because I've been burned by macro expansions going into
infinite loops. Very sore.
Once a macro has been expanded, the form that resulted is
resubmitted for possible further expansion. It is
resubmitted to the same lexical environment in which it was
first expanded. There is no marking of the macrolet which
expanded it as `done' or 'used'. So this works
CL-USER> (macrolet ((cover (&rest stuff)
(if (endp stuff)
''the-end
`(list (quote ,(first stuff))
(cover ,@(rest stuff))))))
(cover a b c))
(A (B (C THE-END)))
(cover a b c) expands to (list 'a (cover b c))
then (list 'a (list 'b (cover c))
then (list 'a (list 'b (list 'c (cover))))
then (list 'a (list 'b (list 'c 'the-end)))
But we can elaborate on Alex's example by using COVER in
both the expansion and the code that generates it.
CL-USER> (macrolet ((cover (&rest stuff)
(format *debug-io* "~&Outer (cover ~A)" stuff)
(length stuff)))
(macrolet ((cover (&rest stuff)
(format *debug-io* "~&Inner (cover ~A)" stuff)
(if (endp stuff)
(cover x y z)
`(list ,(cover stuff)
(cover ,@(rest stuff))))))
(cover a b c)))
Outer (cover (X Y Z))
Outer (cover (STUFF))
Inner (cover (A B C))
Inner (cover (B C))
Inner (cover (C))
Inner (cover NIL)
(1 (1 (1 3)))
Notice CMUCL being quite eager about macroexpanding
macroexpanders. If we quote the call of COVER so it is just
data and doesn't get expanded, the Outer calls are still
made.
Alan Crowe
Edinburgh
Scotland
···········@gmail.com wrote:
> On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
> wrote:
>> rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
>> rr> analogy) somewhat like FLET in the sense that the local macros may not
>> rr> call one another. But what if the desired behavior were more like
>> rr> LABELS, where not only could they call one another, but you could have
>> rr> recursive macro calls as well, for instance.
>>
>> either you're missing the way how macros work -- they do not _call_ each
>> other, but just code generated by one macro might contain references to
>> another one, so it just needs one more round of macroexpansion.
>> or you're doing something impressive like macro-defining-macros, then we'd
>> appreciated if you share this stuff with us!
>>
>> for example,
>>
>> (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
>> (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
>> (repeat-3-times (print "recursive macros are mind-boggling"))))
>>
>> this won't work in single macrolet -- it will complain about
>> n-times-repeater being not defined.
>> i'm afraid i'm not able to invent anything that can't be handled with nested
>> macrolets..
>
> Well, to tell you the truth, Alex, concerning the "calling" part, I
> was merely repeating Graham's words (quote):
>
> "(macrolet ((symbol parameters . body)*)
> Special Operator
> declaration* expression*)
> Evaluates its body with each symbol defined locally to be the
> corresponding
> macro. The expansion functions are defined in the lexical
> environment where
> the macrolet expression occurs. Like f l e t , the local macros
> may not call
> one another."
>
> As you can see, he explicitly says " ... the local macros may not call
> one another." So I guess he's got this calling business all wrong,
> perhaps ;)
>
> I gather, from what you're saying, that the only way to do what I was
> asking is through the use of nested MACROLETs. Am I correct?
>
> Thanks.
..create a MACROLET* macro that does the same thing LET* or LABELS does
(nests for you) .. something like this:
(defmacro macrolet* (definitions &body body)
(if (null definitions)
`(progn ,@body)
`(macrolet (,(first definitions))
(macrolet* ,(rest definitions)
,@body))))
--
Lars Rune N�stdal
http://nostdal.org/
On Apr 13, 2:16 pm, Lars Rune Nøstdal <···········@gmail.com> wrote:
> ···········@gmail.com wrote:
> > On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
> > wrote:
> >> rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
> >> rr> analogy) somewhat like FLET in the sense that the local macros may not
> >> rr> call one another. But what if the desired behavior were more like
> >> rr> LABELS, where not only could they call one another, but you could have
> >> rr> recursive macro calls as well, for instance.
>
> >> either you're missing the way how macros work -- they do not _call_ each
> >> other, but just code generated by one macro might contain references to
> >> another one, so it just needs one more round of macroexpansion.
> >> or you're doing something impressive like macro-defining-macros, then we'd
> >> appreciated if you share this stuff with us!
>
> >> for example,
>
> >> (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
> >> (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
> >> (repeat-3-times (print "recursive macros are mind-boggling"))))
>
> >> this won't work in single macrolet -- it will complain about
> >> n-times-repeater being not defined.
> >> i'm afraid i'm not able to invent anything that can't be handled with nested
> >> macrolets..
>
> > Well, to tell you the truth, Alex, concerning the "calling" part, I
> > was merely repeating Graham's words (quote):
>
> > "(macrolet ((symbol parameters . body)*)
> > Special Operator
> > declaration* expression*)
> > Evaluates its body with each symbol defined locally to be the
> > corresponding
> > macro. The expansion functions are defined in the lexical
> > environment where
> > the macrolet expression occurs. Like f l e t , the local macros
> > may not call
> > one another."
>
> > As you can see, he explicitly says " ... the local macros may not call
> > one another." So I guess he's got this calling business all wrong,
> > perhaps ;)
>
> > I gather, from what you're saying, that the only way to do what I was
> > asking is through the use of nested MACROLETs. Am I correct?
>
> > Thanks.
>
> ..create a MACROLET* macro that does the same thing LET* or LABELS does
> (nests for you) .. something like this:
>
> (defmacro macrolet* (definitions &body body)
> (if (null definitions)
> `(progn ,@body)
> `(macrolet (,(first definitions))
> (macrolet* ,(rest definitions)
> ,@body))))
>
> --
> Lars Rune Nøstdalhttp://nostdal.org/
That is so cool! Just goes to show the power of macros :)
Thank you Lars.
One last thing. I've just been going over Paul Graham's book, and I
simply can't manage to find a confirmation of his statement. Namely,
".. Like FLET, the local macros may not call one another."
Are we sure this is correct in the first place???
I wonder if Mr. Pitman would be so kind as to illuminate us on this
matter.
On Apr 13, 2:57 pm, ···········@gmail.com wrote:
> On Apr 13, 2:16 pm, Lars Rune Nøstdal <···········@gmail.com> wrote:
>
>
>
> > ···········@gmail.com wrote:
> > > On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
> > > wrote:
> > >> rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
> > >> rr> analogy) somewhat like FLET in the sense that the local macros may not
> > >> rr> call one another. But what if the desired behavior were more like
> > >> rr> LABELS, where not only could they call one another, but you could have
> > >> rr> recursive macro calls as well, for instance.
>
> > >> either you're missing the way how macros work -- they do not _call_ each
> > >> other, but just code generated by one macro might contain references to
> > >> another one, so it just needs one more round of macroexpansion.
> > >> or you're doing something impressive like macro-defining-macros, then we'd
> > >> appreciated if you share this stuff with us!
>
> > >> for example,
>
> > >> (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
> > >> (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
> > >> (repeat-3-times (print "recursive macros are mind-boggling"))))
>
> > >> this won't work in single macrolet -- it will complain about
> > >> n-times-repeater being not defined.
> > >> i'm afraid i'm not able to invent anything that can't be handled with nested
> > >> macrolets..
>
> > > Well, to tell you the truth, Alex, concerning the "calling" part, I
> > > was merely repeating Graham's words (quote):
>
> > > "(macrolet ((symbol parameters . body)*)
> > > Special Operator
> > > declaration* expression*)
> > > Evaluates its body with each symbol defined locally to be the
> > > corresponding
> > > macro. The expansion functions are defined in the lexical
> > > environment where
> > > the macrolet expression occurs. Like f l e t , the local macros
> > > may not call
> > > one another."
>
> > > As you can see, he explicitly says " ... the local macros may not call
> > > one another." So I guess he's got this calling business all wrong,
> > > perhaps ;)
>
> > > I gather, from what you're saying, that the only way to do what I was
> > > asking is through the use of nested MACROLETs. Am I correct?
>
> > > Thanks.
>
> > ..create a MACROLET* macro that does the same thing LET* or LABELS does
> > (nests for you) .. something like this:
>
> > (defmacro macrolet* (definitions &body body)
> > (if (null definitions)
> > `(progn ,@body)
> > `(macrolet (,(first definitions))
> > (macrolet* ,(rest definitions)
> > ,@body))))
>
> > --
> > Lars Rune Nøstdalhttp://nostdal.org/
>
> That is so cool! Just goes to show the power of macros :)
>
> Thank you Lars.
>
> One last thing. I've just been going over Paul Graham's book, and I
> simply can't manage to find a confirmation of his statement. Namely,
> ".. Like FLET, the local macros may not call one another."
>
> Are we sure this is correct in the first place???
>
> I wonder if Mr. Pitman would be so kind as to illuminate us on this
> matter.
Sorry, I meant to say I can't find a confirmation of Graham's
statement in the HyperSpec.
In article
<····································@8g2000hse.googlegroups.com>,
···········@gmail.com wrote:
> On Apr 13, 2:16 pm, Lars Rune N�stdal <···········@gmail.com> wrote:
> > ···········@gmail.com wrote:
> > > On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
> > > wrote:
> > >> rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
> > >> rr> analogy) somewhat like FLET in the sense that the local macros may
> > >> not
> > >> rr> call one another. But what if the desired behavior were more like
> > >> rr> LABELS, where not only could they call one another, but you could
> > >> have
> > >> rr> recursive macro calls as well, for instance.
> >
> > >> either you're missing the way how macros work -- they do not _call_ each
> > >> other, but just code generated by one macro might contain references to
> > >> another one, so it just needs one more round of macroexpansion.
> > >> or you're doing something impressive like macro-defining-macros, then
> > >> we'd
> > >> appreciated if you share this stuff with us!
> >
> > >> for example,
> >
> > >> (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect
> > >> ,x))))
> > >> (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
> > >> (repeat-3-times (print "recursive macros are mind-boggling"))))
> >
> > >> this won't work in single macrolet -- it will complain about
> > >> n-times-repeater being not defined.
> > >> i'm afraid i'm not able to invent anything that can't be handled with
> > >> nested
> > >> macrolets..
> >
> > > Well, to tell you the truth, Alex, concerning the "calling" part, I
> > > was merely repeating Graham's words (quote):
> >
> > > "(macrolet ((symbol parameters . body)*)
> > > Special Operator
> > > declaration* expression*)
> > > Evaluates its body with each symbol defined locally to be the
> > > corresponding
> > > macro. The expansion functions are defined in the lexical
> > > environment where
> > > the macrolet expression occurs. Like f l e t , the local macros
> > > may not call
> > > one another."
> >
> > > As you can see, he explicitly says " ... the local macros may not call
> > > one another." So I guess he's got this calling business all wrong,
> > > perhaps ;)
> >
> > > I gather, from what you're saying, that the only way to do what I was
> > > asking is through the use of nested MACROLETs. Am I correct?
> >
> > > Thanks.
> >
> > ..create a MACROLET* macro that does the same thing LET* or LABELS does
> > (nests for you) .. something like this:
> >
> > (defmacro macrolet* (definitions &body body)
> > (if (null definitions)
> > `(progn ,@body)
> > `(macrolet (,(first definitions))
> > (macrolet* ,(rest definitions)
> > ,@body))))
> >
> > --
> > Lars Rune N�stdalhttp://nostdal.org/
>
> That is so cool! Just goes to show the power of macros :)
>
> Thank you Lars.
>
> One last thing. I've just been going over Paul Graham's book, and I
> simply can't manage to find a confirmation of his statement. Namely,
> ".. Like FLET, the local macros may not call one another."
>
> Are we sure this is correct in the first place???
It is correct, but potentially misleading. If you have:
(macrolet ((m1 ...) (m2 ...)) ...)
the m1 may not use m2 in its macroexpander, but m2 may appear in the
expansion of m1 (and vice versa). So, for example, this works:
(macrolet ((oddm (n) (if (= n 0) nil (if (= n 1) t `(evenm ,(1- n)))))
(evenm (n) (if (= n 0) t (if (= n 1) nil `(oddm ,(1- n))))))
...)
but this doesn't:
(macrolet ((oddm (n) (if (= n 0) nil (if (= n 1) t (evenm (1- n)))))
(evenm (n) (if (= n 0) t (if (= n 1) nil (oddm (1- n))))))
...)
rg
Ron Garret <·········@flownet.com> writes:
> In article
> <····································@8g2000hse.googlegroups.com>,
> ···········@gmail.com wrote:
> [...]
> > One last thing. I've just been going over Paul Graham's book, and I
> > simply can't manage to find a confirmation of his statement. Namely,
> > ".. Like FLET, the local macros may not call one another."
> >
> > Are we sure this is correct in the first place???
Note that call one another does not mean reference one another in an
expansion. The expansion is processed after you're into the body,
and at that point all of the names are established as bindings.
Only the body of the _expander_ can be relevant, since only in the
_expander_ is there any issue of what is yet scoped when you're halfway
through the bindings.
I believe Ron has it right here:
> It is correct, but potentially misleading. If you have:
>
> (macrolet ((m1 ...) (m2 ...)) ...)
>
> the m1 may not use m2 in its macroexpander, but m2 may appear in the
> expansion of m1 (and vice versa). So, for example, this works:
>
> (macrolet ((oddm (n) (if (= n 0) nil (if (= n 1) t `(evenm ,(1- n)))))
> (evenm (n) (if (= n 0) t (if (= n 1) nil `(oddm ,(1- n))))))
> ...)
>
> but this doesn't:
>
> (macrolet ((oddm (n) (if (= n 0) nil (if (= n 1) t (evenm (1- n)))))
> (evenm (n) (if (= n 0) t (if (= n 1) nil (oddm (1- n))))))
> ...)
A related example:
(macrolet ((foo (x) ``(expanded-foo ,,x)))
(macrolet ((bar (x) (print (foo x)) x))
(bar (foo (+ 1 1)))))
(EXPANDED-FOO (FOO (+ 1 1)))
=> (EXPANDED-FOO 2)
(macrolet ((foo (x) ``(expanded-foo ,,x))
(bar (x) (print (foo x)) x))
(bar (foo (+ 1 1))))
Error: Undefined function FOO called with arguments ((FOO (+ 1 1))).
Also, btw, an even more obscure example where you might think this all
mattered would be when calling MACROEXPAND in the expander, since it
sort of appears to happen "in" the expander, might be the following.
But note again that really it doesn't happen "in" the expander, it
happens in function calls, using the env which is generated relative
to the body form, not the form in the expander. So by that time the
bindings are established and you don't get snagged by the
not-yet-defined-ness that happens when processing the binding
definitions themselves.
(macrolet ((foo (x) ``(expanded-foo ,,x))
(bar (x &environment env)
;; I wouldn't ordinarily do this this way,
;; and don't recommend this programming style
;; but I wanted to make a point about what
;; things one can rely on here and what one
;; can't... and, in fact, EVAL is pretty much
;; what top-level macros are doing after the
;; lexical phase (macro expansion) is dismissed.
;; (In the truly general case, you'd have to worry
;; about references to macros in the macro body,
;; but my example handwaves away that scenario, so
;; squeak by without a recursive MACROEXPAND-ALL.)
(progv (list 'x) (list x)
(print (eval `(locally
(declare (special x))
,(macroexpand '(foo x) env)))))
(macroexpand x env)))
(bar (foo (+ 1 1))))
(EXPANDED-FOO (FOO (+ 1 1)))
=> (EXPANDED-FOO 2)
Then again, all in all, I don't generally recommend writing macros
that need to do this. So I'm not sure any of this matters much.
- - - -
Footnote (really apropos another thread where this came up recently,
but it rears its ugly head again here as a tangential element):
I really don't like it when implementations make me put in (locally
(declare (special x)) ...) but I put that there for people who like
strict conformance. It's true the spec requires it, but the
rationale for not making free variables defaultly special wasn't to
allow implementations to randomly hit people's knuckles with a ruler,
it was to allow them to add global lexicals compatibly, by reserving
them space to do that. For implementations who've gone to the
trouble to do that, I applaud them and will be happy to adjust my
programs if/when I'm actually using those implementations. But since
I've seen none of them do it and certainly no one promote it as
style everyone should adopt, I don't see the point of the ones who
think there are no variables other than specials telling me I've done
something ambiguous by not specifying. The market was intended to sort
out that gray area, and my personal marketplace consumer behavior is
to prefer implementations that don't make me do gratuitous work for
nothing. I like being able to just SETQ toplevel variables and know I
am setting the symbol value and I like being able to eval forms with
free variable references and know I'm getting symbol values.
(Frankly, even if I were adding lexicals, I'd probably just make
deflexical do an override of the individual variable's default behavior
and I'd still leave undeclared variables defaulting to special,
in that way encouraging people to declare their free variables, and
at the same time making legacy behavior fully compatible without all those
silly declarations.)
On Apr 14, 12:49 am, Kent M Pitman <······@nhplace.com> wrote:
> Ron Garret <·········@flownet.com> writes:
> > In article
> > <····································@8g2000hse.googlegroups.com>,
> > ···········@gmail.com wrote:
> > [...]
> > > One last thing. I've just been going over Paul Graham's book, and I
> > > simply can't manage to find a confirmation of his statement. Namely,
> > > ".. Like FLET, the local macros may not call one another."
>
> > > Are we sure this is correct in the first place???
>
> Note that call one another does not mean reference one another in an
> expansion. The expansion is processed after you're into the body,
> and at that point all of the names are established as bindings.
>
> Only the body of the _expander_ can be relevant, since only in the
> _expander_ is there any issue of what is yet scoped when you're halfway
> through the bindings.
>
> I believe Ron has it right here:
>
>
>
> > It is correct, but potentially misleading. If you have:
>
> > (macrolet ((m1 ...) (m2 ...)) ...)
>
> > the m1 may not use m2 in its macroexpander, but m2 may appear in the
> > expansion of m1 (and vice versa). So, for example, this works:
>
> > (macrolet ((oddm (n) (if (= n 0) nil (if (= n 1) t `(evenm ,(1- n)))))
> > (evenm (n) (if (= n 0) t (if (= n 1) nil `(oddm ,(1- n))))))
> > ...)
>
> > but this doesn't:
>
> > (macrolet ((oddm (n) (if (= n 0) nil (if (= n 1) t (evenm (1- n)))))
> > (evenm (n) (if (= n 0) t (if (= n 1) nil (oddm (1- n))))))
> > ...)
>
> A related example:
>
> (macrolet ((foo (x) ``(expanded-foo ,,x)))
> (macrolet ((bar (x) (print (foo x)) x))
> (bar (foo (+ 1 1)))))
>
> (EXPANDED-FOO (FOO (+ 1 1)))
> => (EXPANDED-FOO 2)
>
> (macrolet ((foo (x) ``(expanded-foo ,,x))
> (bar (x) (print (foo x)) x))
> (bar (foo (+ 1 1))))
> Error: Undefined function FOO called with arguments ((FOO (+ 1 1))).
>
> Also, btw, an even more obscure example where you might think this all
> mattered would be when calling MACROEXPAND in the expander, since it
> sort of appears to happen "in" the expander, might be the following.
> But note again that really it doesn't happen "in" the expander, it
> happens in function calls, using the env which is generated relative
> to the body form, not the form in the expander. So by that time the
> bindings are established and you don't get snagged by the
> not-yet-defined-ness that happens when processing the binding
> definitions themselves.
>
> (macrolet ((foo (x) ``(expanded-foo ,,x))
> (bar (x &environment env)
> ;; I wouldn't ordinarily do this this way,
> ;; and don't recommend this programming style
> ;; but I wanted to make a point about what
> ;; things one can rely on here and what one
> ;; can't... and, in fact, EVAL is pretty much
> ;; what top-level macros are doing after the
> ;; lexical phase (macro expansion) is dismissed.
> ;; (In the truly general case, you'd have to worry
> ;; about references to macros in the macro body,
> ;; but my example handwaves away that scenario, so
> ;; squeak by without a recursive MACROEXPAND-ALL.)
> (progv (list 'x) (list x)
> (print (eval `(locally
> (declare (special x))
> ,(macroexpand '(foo x) env)))))
> (macroexpand x env)))
> (bar (foo (+ 1 1))))
>
> (EXPANDED-FOO (FOO (+ 1 1)))
> => (EXPANDED-FOO 2)
>
> Then again, all in all, I don't generally recommend writing macros
> that need to do this. So I'm not sure any of this matters much.
>
> - - - -
>
> Footnote (really apropos another thread where this came up recently,
> but it rears its ugly head again here as a tangential element):
>
> I really don't like it when implementations make me put in (locally
> (declare (special x)) ...) but I put that there for people who like
> strict conformance. It's true the spec requires it, but the
> rationale for not making free variables defaultly special wasn't to
> allow implementations to randomly hit people's knuckles with a ruler,
> it was to allow them to add global lexicals compatibly, by reserving
> them space to do that. For implementations who've gone to the
> trouble to do that, I applaud them and will be happy to adjust my
> programs if/when I'm actually using those implementations. But since
> I've seen none of them do it and certainly no one promote it as
> style everyone should adopt, I don't see the point of the ones who
> think there are no variables other than specials telling me I've done
> something ambiguous by not specifying. The market was intended to sort
> out that gray area, and my personal marketplace consumer behavior is
> to prefer implementations that don't make me do gratuitous work for
> nothing. I like being able to just SETQ toplevel variables and know I
> am setting the symbol value and I like being able to eval forms with
> free variable references and know I'm getting symbol values.
>
> (Frankly, even if I were adding lexicals, I'd probably just make
> deflexical do an override of the individual variable's default behavior
> and I'd still leave undeclared variables defaulting to special,
> in that way encouraging people to declare their free variables, and
> at the same time making legacy behavior fully compatible without all those
> silly declarations.)
Thanks for the very clear response Mr. Pitman (and to Ron Garret as
well). It was much more than I was even asking for :) Just one last
thing. I couldn't actually pinpoint the place in the HyperSpec where
it says that MACROLET has the above mentioned characteristic (a la
FLET so to speak). Other than Graham's book, there's no other place
where I've seen it clearly stated. Could you indicate where that
specific detail is located?
Thanks again.
In article
<····································@a22g2000hsc.googlegroups.com>,
···········@gmail.com wrote:
> I couldn't actually pinpoint the place in the HyperSpec where
> it says that MACROLET has the above mentioned characteristic (a la
> FLET so to speak). Other than Graham's book, there's no other place
> where I've seen it clearly stated. Could you indicate where that
> specific detail is located?
There isn't "a place" where this behavior is described. It's an
"emergent property" of the definition of macrolet (in section 5.3) and
the rules for how macroexpansion is performed (in section 3.1.2.1.2.2).
rg
···········@gmail.com writes:
> Thanks for the very clear response Mr. Pitman (and to Ron Garret as
> well). It was much more than I was even asking for :) Just one last
> thing. I couldn't actually pinpoint the place in the HyperSpec where
> it says that MACROLET has the above mentioned characteristic (a la
> FLET so to speak). Other than Graham's book, there's no other place
> where I've seen it clearly stated. Could you indicate where that
> specific detail is located?
I think it's probably the implication of this statement from the
penultimate paragraph of the macrolet dictionary entry, though I will
be the first to criticize the wording as lacking in perspicuity:
The macro-expansion functions defined by macrolet are defined
in the lexical environment in which the macrolet form appears.
On Apr 14, 3:04 pm, Kent M Pitman <······@nhplace.com> wrote:
> ···········@gmail.com writes:
> > Thanks for the very clear response Mr. Pitman (and to Ron Garret as
> > well). It was much more than I was even asking for :) Just one last
> > thing. I couldn't actually pinpoint the place in the HyperSpec where
> > it says that MACROLET has the above mentioned characteristic (a la
> > FLET so to speak). Other than Graham's book, there's no other place
> > where I've seen it clearly stated. Could you indicate where that
> > specific detail is located?
>
> I think it's probably the implication of this statement from the
> penultimate paragraph of the macrolet dictionary entry, though I will
> be the first to criticize the wording as lacking in perspicuity:
>
> The macro-expansion functions defined by macrolet are defined
> in the lexical environment in which the macrolet form appears.
OK. Thanks again.
In article <·············@nhplace.com>,
Kent M Pitman <······@nhplace.com> wrote:
> Footnote (really apropos another thread where this came up recently,
> but it rears its ugly head again here as a tangential element):
>
> I really don't like it when implementations make me put in (locally
> (declare (special x)) ...) but I put that there for people who like
> strict conformance. It's true the spec requires it, but the
> rationale for not making free variables defaultly special wasn't to
> allow implementations to randomly hit people's knuckles with a ruler,
> it was to allow them to add global lexicals compatibly, by reserving
> them space to do that. For implementations who've gone to the
> trouble to do that, I applaud them and will be happy to adjust my
> programs if/when I'm actually using those implementations. But since
> I've seen none of them do it and certainly no one promote it as
> style everyone should adopt, I don't see the point of the ones who
> think there are no variables other than specials telling me I've done
> something ambiguous by not specifying. The market was intended to sort
> out that gray area, and my personal marketplace consumer behavior is
> to prefer implementations that don't make me do gratuitous work for
> nothing. I like being able to just SETQ toplevel variables and know I
> am setting the symbol value and I like being able to eval forms with
> free variable references and know I'm getting symbol values.
>
> (Frankly, even if I were adding lexicals, I'd probably just make
> deflexical do an override of the individual variable's default behavior
> and I'd still leave undeclared variables defaulting to special,
> in that way encouraging people to declare their free variables, and
> at the same time making legacy behavior fully compatible without all those
> silly declarations.)
That would exclude the possibility of doing deferred bindings on global
lexicals, which IMHO is a handy dandy feature. IMHO a better solution
would be to have some kind of user-manipulable
free-variable-reference-hook or some such thing (along with an
undefined-function-reference-hook). But since the spec is about as
likely to change as George Bush is to withdraw from Iraq this is all
moot anyway.
rg
···········@gmail.com writes:
> One last thing. I've just been going over Paul Graham's book, and I
> simply can't manage to find a confirmation of his statement. Namely,
> ".. Like FLET, the local macros may not call one another."
>
> Are we sure this is correct in the first place???
Well, it could be confusing. It depends on what one meas by "call one
another".
That is because, the way I see it, there are really two parts to a
macro. There is the expanded code that the macro produces (the
expansion) and there is the computation that arrives at that
computation.
Each macro form in the body of the MACROLET is EXPANDED, and then
subsequently processed recursively. Since this execution is in the body
of the MACROLET, it means that any references to macros in that body use
the local binding of the macro expansion. Note that this really isn't
at all "hygenic". There is an evil example in the HyperSpec that shows
the capture of the inner macro expansion using a globally-defined macro
that expands into code that refers to the name bound by the MACROLET.
Since macros expand to code, they don't really have any internal scope
in the expansion. That leaves open the question of whether you could
use a MACROLET macro in the code that computes the expansion. Since the
specification says that the change in the expansion function is only
active in the body of the macrolet (rather than also in the definition
forms), that means you can't use a MACROLET macro to compute the
expansion of any sibling macros.
--
Thomas A. Russ, USC/Information Sciences Institute
LRN> ..create a MACROLET* macro that does the same thing LET* or LABELS
LRN> does (nests for you) .. something like this:
LABELS does more than nesting, it's not _that_ easy to emulate it -- you
need sort of Y combinator to do this.
see here: http://home.pipeline.com/~hbaker1/MetaCircular.html
···········@gmail.com wrote:
> On Apr 13, 1:16 pm, "Alex Mizrahi" <········@users.sourceforge.net>
> wrote:
>> rr> I read in Paul Graham's Ansi Common Lisp that MACROLET behaves (in
>> rr> analogy) somewhat like FLET in the sense that the local macros may not
>> rr> call one another. But what if the desired behavior were more like
>> rr> LABELS, where not only could they call one another, but you could have
>> rr> recursive macro calls as well, for instance.
>>
>> either you're missing the way how macros work -- they do not _call_ each
>> other, but just code generated by one macro might contain references to
>> another one, so it just needs one more round of macroexpansion.
>> or you're doing something impressive like macro-defining-macros, then we'd
>> appreciated if you share this stuff with us!
>>
>> for example,
>>
>> (macrolet ((n-times-repeater (n x) ``(progn ,@(loop repeat ,n collect ,x))))
>> (macrolet ((repeat-3-times (y) (n-times-repeater 3 y)))
>> (repeat-3-times (print "recursive macros are mind-boggling"))))
>>
>> this won't work in single macrolet -- it will complain about
>> n-times-repeater being not defined.
>> i'm afraid i'm not able to invent anything that can't be handled with nested
>> macrolets..
>
> Well, to tell you the truth, Alex, concerning the "calling" part, I
> was merely repeating Graham's words (quote):
>
> "(macrolet ((symbol parameters . body)*)
> Special Operator
> declaration* expression*)
> Evaluates its body with each symbol defined locally to be the
> corresponding
> macro. The expansion functions are defined in the lexical
> environment where
> the macrolet expression occurs. Like f l e t , the local macros
> may not call
> one another."
>
> As you can see, he explicitly says " ... the local macros may not call
> one another." So I guess he's got this calling business all wrong,
> perhaps ;)
Indeed, he should have said something like "invoke each other."
"Calling" macros creates the wrong intuition.
> I gather, from what you're saying, that the only way to do what I was
> asking is through the use of nested MACROLETs. Am I correct?
It's rare that you think of macros invoking each other in the same way
that functions recursively call each other. Of course, a macro may just
use (invoke) other macros in their definitions, but that's not a very
special thing to do. Indeed, it happens more often than you might be
aware of.
What's more interesting, though, is that the process of macro expansion
may be recursive. That doesn't happen so often, but is an interesting case.
Here is an example:
(defmacro my-let* ((&rest bindings) &body body)
(if bindings
`(let (,(first bindings))
(my-let* ,(rest bindings) ,@body))
`(progn ,@body)))
Here, my-let* expands into a use of itself. You have the same
requirements as for recursive functions: You need a base case, and in
each recursive step, whatever the macro does should be a step closer to
that base case, in order to guarantee that expansion process terminates.
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
rr> Well, to tell you the truth, Alex, concerning the "calling" part, I
rr> was merely repeating Graham's words (quote):
rr> "(macrolet ((symbol parameters . body)*)
rr> Special Operator
rr> declaration* expression*)
rr> Evaluates its body with each symbol defined locally to be the
rr> corresponding
rr> macro. The expansion functions are defined in the lexical
rr> environment where
rr> the macrolet expression occurs. Like f l e t , the local macros
rr> may not call
rr> one another."
rr> As you can see, he explicitly says " ... the local macros may not call
rr> one another."
that is correct. but calling local macros from each other is not what people
want in 99.9% cases.
they might macroexpand recursively, that that just works.
rr> I gather, from what you're saying, that the only way to do what I was
rr> asking is through the use of nested MACROLETs. Am I correct?
i still haven't seen what exactly are you doing, so i don't know whether it
should be handled with single macrolet, two nested ones, or it's not
possible to in lisp.
my best guess is that you just need recursive macroexpansion, and this just
works with single macrolet