[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: semantics of ?=
- To: address@hidden
- Subject: Re: semantics of ?=
- From: Bruce Hoult <address@hidden>
- Date: Sun, 15 Sep 2002 20:00:02 -0400
- Organization: none
- References: <200209151605.g8FG5xML008065@life.ai.mit.edu>
- Sender: "Gregory T. Sullivan" <address@hidden>
- User-agent: MT-NewsWatcher/3.2 (PPC Mac OS X)
- Xref: traf.lcs.mit.edu comp.lang.dylan:14359
In article <200209151605.g8FG5xML008065@life.ai.mit.edu>,
Gabor Greif <gabor@mac.com> wrote:
> We had quite some discussion on IRC channel #dylan about what the
> intensional name capture by ?= should accomplish.
Indeed.
> My idea is: ?=name in a macro expansion behaves exactly the same _as_if_
> the users code had \name in that position.
Absolutely. The question is: who is the user?
I believe that the user is the person who typed in the call to the
macro, A, whose expansion contains a use of ?=.
Gabor seems to believe that the user is the person who types in a call
of a macro C, which in its expansion uses macro B, which in it's
expansion uses macro A, which in its expansion uses ?=.
In my opinion, Gabor's intepretation violates several basic tenets:
- the principle of least surprise.
- the principle that a macro that evaluates each of its arguments
exactly once, in the appropriate order, has the same semantics as a
function with the same body.
[snipped examples of how Gwydion Dylan currently works, and indeed how
it would *continue* to work under my interpretation]
> ------------------------------------------------------------
>
> Now, Bruce hoped to be able to refer to a macro-mentioned hygienic name
> by using ?=.
>
> Something like this:
>
> begin
> let it = 5;
> format-out("captured: %d\n", it-binder(42, it-capturer2()));
> end;
>
> My opinion is that this should _never_ result in "captured: 42".
I agree totally. That should never work. It is, however, *quite*
different to what I want to work. it-capturer2, when expanded, refers
to a name "it" in the scope into which it is expanded -- namely code
written by the person who typed this begin/end block. it-binder makes
no attempt to refer to the same scope.
What I want to have work can not be expressed by Gabor's macros.
Allow me to give an example smaller than the previous one I posted here.
I suspect that there has so far been very little use of intentional
violation of hygiene in Dylan. Even in Common Lisp, where it is the
default and has to be specifically avoided, it seems that a rather small
minority of macros intentionally use variable capture -- and most of
those are the "anaphoric" macros described in Chapter 14 of _On Lisp_
(http://www.paulgraham.com/onlisptext.html).
>From P191:
(defmacro awhile (expr &body body)
`(do ((it ,expr ,expr))
((not it))
,@body))
(awhile (poll *fridge*)
(eat it))
In Dylan this will be:
define macro awhile
{while (?:expr) ?:body end} =>
{for (?=it = ?expr then ?expr,
while: ?=it)
?body
end}
end macro;
awhile(poll($fridge))
eat(it)
end
Presumably it would be reasonable to assume that this should work
properly in Dylan. Let's fill in the details so we can run it and see:
---------------------------------------
module: capture
define macro awhile
{awhile (?exp:expression) ?:body end} =>
{for (?=it = ?exp then ?exp,
while: ?=it)
?body
end}
end macro;
define variable $fridge = as(<deque>, #("pizza", "steak", "yoghurt"));
define method poll(x)
~x.empty? & x.pop
end;
define method eat(x)
format-out("Eating %s\n", x);
end;
awhile(poll($fridge))
eat(it)
end
---------------------------------------
bruce@k7:~/programs/dylan/capture > ./capture
Eating pizza
Eating steak
Eating yoghurt
bruce@k7:~/programs/dylan/capture >
---------------------------------------
Works fine.
Now, it would be reasonable to use awhile() in a function, rather than
at the top level:
define method pig-out(where)
awhile(poll(where))
eat(it)
end
end;
pig-out($fridge);
Works fine. Try it.
It would also be reasonable to turn pig-out into an inline function, or
a macro. Let's try a macro:
---------------------------------------
module: capture
define macro awhile
{awhile (?exp:expression) ?:body end} =>
{for (?=it = ?exp then ?exp,
while: ?=it)
?body
end}
end macro;
define variable $fridge = as(<deque>, #("pizza", "steak", "yoghurt"));
define method poll(x)
~x.empty? & x.pop
end;
define method eat(x)
format-out("Eating %s\n", x);
end;
define macro pig-out
{pig-out(?_where:expression)}
=> {let where = ?_where;
awhile(poll(where))
eat(it)
end}
end;
pig-out($fridge);
---------------------------------------
In Top level form.:
"capture.dylan", line 25, characters 15 through 16:
eat(it)
^^
Error: Undefined variable: it
---------------------------------------
Oops! ?= working the way Gabor likes it has injected "it" directly into
the top level and it is not visible inside the expansion of pig-out.
I think it is surprising and wrong that perfectly reasonable code that
uses awhile() suddenly stops working if you use it in the expansion of a
macro.
This behaviour will prevent a *huge* number of the macros in _On Lisp_
from being converted into Dylan.
I believe that use of ?=it in awhile() should refer to a variable of
that name in the textual environment in which awhile is mentioned. It
is the author of pig-out that is the "user" of awhile, NOT the person
who wrote "pig-out($fridge)".
-- Bruce