newbie question: do macros in Lisp and Scheme have equal expressive power?

26 views
Skip to first unread message

min...@gmail.com

unread,
Dec 8, 2006, 2:43:29 AM12/8/06
to
In terms of expressive power, are they equal (in their own language)?
and do they have any difference?

BTW, which Lisp/Scheme compiler implementation produce the fastest
executable (x86, Linux)?

Thanks.

Pascal Costanza

unread,
Dec 8, 2006, 3:12:33 AM12/8/06
to
min...@gmail.com wrote:
> In terms of expressive power, are they equal (in their own language)?
> and do they have any difference?

The default macro system of R5RS Scheme is more restricted than Common
Lisp's macro system, but Scheme' syntax-case (which is going to be part
of R6RS) is more or less on par wrt expressive power.

The other important question is which one is more convenient to use. Of
course, you can decide this only for yourself.

> BTW, which Lisp/Scheme compiler implementation produce the fastest
> executable (x86, Linux)?

Efficiency largely depends on the kinds of problems you want to solve.
Such questions cannot be answered in general.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Rob Warnock

unread,
Dec 8, 2006, 6:41:40 AM12/8/06
to
Pascal Costanza <p...@p-cos.net> wrote:
+---------------

| min...@gmail.com wrote:
| > In terms of expressive power, are they equal (in their own language)?
| > and do they have any difference?
|
| The default macro system of R5RS Scheme is more restricted than Common
| Lisp's macro system, but Scheme' syntax-case (which is going to be part
| of R6RS) is more or less on par wrt expressive power.
+---------------

Plus, many [most?] Scheme implementations provide
CL-style "defmacro" (or equivalent) as an extension.


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Pascal Costanza

unread,
Dec 8, 2006, 7:06:38 AM12/8/06
to
Rob Warnock wrote:
> Pascal Costanza <p...@p-cos.net> wrote:
> +---------------
> | min...@gmail.com wrote:
> | > In terms of expressive power, are they equal (in their own language)?
> | > and do they have any difference?
> |
> | The default macro system of R5RS Scheme is more restricted than Common
> | Lisp's macro system, but Scheme' syntax-case (which is going to be part
> | of R6RS) is more or less on par wrt expressive power.
> +---------------
>
> Plus, many [most?] Scheme implementations provide
> CL-style "defmacro" (or equivalent) as an extension.

An important ingredient of the Common Lisp macro system is the
&environment parameter that allows you to reason about the lexical
environment in which a macro is expanded. This seems to be typically
missing in Scheme versions of CL-style macros and makes a big difference
wrt expressiveness.

macroexpand-1 and macroexpand are also important elements of the CL
macro system.

Alex Mizrahi

unread,
Dec 8, 2006, 8:41:43 AM12/8/06
to
(message (Hello 'min...@gmail.com)
(you :wrote :on '(7 Dec 2006 23:43:29 -0800))
(

m> BTW, which Lisp/Scheme compiler implementation produce the fastest
m> executable (x86, Linux)?

there are Common Lisp implementations (ECL, GCL) that compile function using
C compiler (they produce C files), so if you specify enough type
declaration, it can be as fast as C compiler.

OTOH if you don't want to make too much declarations, type inference might
help you.

in general, commercial implementations (ACL, LispWorks) tend to produce fast
"executables".

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"People who lust for the Feel of keys on their fingertips (c) Inity")


samth

unread,
Dec 8, 2006, 9:49:03 AM12/8/06
to

Pascal Costanza wrote:
> min...@gmail.com wrote:
> > In terms of expressive power, are they equal (in their own language)?
> > and do they have any difference?
>
> The default macro system of R5RS Scheme is more restricted than Common
> Lisp's macro system, but Scheme' syntax-case (which is going to be part
> of R6RS) is more or less on par wrt expressive power.

This isn't quite correct - because of referential transparency, CL
macros cannot replicate the behavior of syntax-rules or syntax-case
macros. Therefore, CL macros are incomparable with syntax-rules.

Further, in the sense of Felleisen's "On the Expressive Power of
Programming Languages", adding gensym is not a macro-expressible (in
the technical sense of that paper) transformation, and thus the
capacity for hygiene also gives more expressiveness to
syntax-{rules,case} macros.

sam th

Pascal Bourguignon

unread,
Dec 8, 2006, 10:05:19 AM12/8/06
to
"samth" <sam...@gmail.com> writes:

Perhaps "theorical expressiveness". What I constat (but I'm no scheme
specialist), is that I write clearer and shorter macros in CL than in
scheme. For me, in practice, CL is at least twice more expressive than
Scheme, since I need half CL code than "equivalent" Scheme code.

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

"This machine is a piece of GAGH! I need dual Opteron 850
processors if I am to do battle with this code!"

Pascal Costanza

unread,
Dec 8, 2006, 10:10:27 AM12/8/06
to
samth wrote:
> Pascal Costanza wrote:
>> min...@gmail.com wrote:
>>> In terms of expressive power, are they equal (in their own language)?
>>> and do they have any difference?
>> The default macro system of R5RS Scheme is more restricted than Common
>> Lisp's macro system, but Scheme' syntax-case (which is going to be part
>> of R6RS) is more or less on par wrt expressive power.
>
> This isn't quite correct - because of referential transparency, CL
> macros cannot replicate the behavior of syntax-rules or syntax-case
> macros. Therefore, CL macros are incomparable with syntax-rules.

That's incorrect. Paul Graham shows in "On Lisp" a number of techniques
how to do this manually, and they are straightforward and require only
local changes to your source code. It's also possible to embed an
extension in CL that adds semi-automatic referential transparency in a
portable way. (I have an implementation, and plan to report on this.)

> Further, in the sense of Felleisen's "On the Expressive Power of
> Programming Languages", adding gensym is not a macro-expressible (in
> the technical sense of that paper) transformation, and thus the
> capacity for hygiene also gives more expressiveness to
> syntax-{rules,case} macros.

I don't get what you want to say here. Could you elaborate?

Pascal Costanza

unread,
Dec 8, 2006, 10:13:01 AM12/8/06
to
Pascal Costanza wrote:
> samth wrote:
>> Pascal Costanza wrote:
>>> min...@gmail.com wrote:
>>>> In terms of expressive power, are they equal (in their own language)?
>>>> and do they have any difference?
>>> The default macro system of R5RS Scheme is more restricted than Common
>>> Lisp's macro system, but Scheme' syntax-case (which is going to be part
>>> of R6RS) is more or less on par wrt expressive power.
>>
>> This isn't quite correct - because of referential transparency, CL
>> macros cannot replicate the behavior of syntax-rules or syntax-case
>> macros. Therefore, CL macros are incomparable with syntax-rules.
>
> That's incorrect. Paul Graham shows in "On Lisp" a number of techniques
> how to do this manually, and they are straightforward and require only
> local changes to your source code. It's also possible to embed an
> extension in CL that adds semi-automatic referential transparency in a
> portable way. (I have an implementation, and plan to report on this.)
>
>> Further, in the sense of Felleisen's "On the Expressive Power of
>> Programming Languages", adding gensym is not a macro-expressible (in
>> the technical sense of that paper) transformation, and thus the
>> capacity for hygiene also gives more expressiveness to
>> syntax-{rules,case} macros.
>
> I don't get what you want to say here. Could you elaborate?

Maybe that's important: I regard gensym (and related symbol
functionality) as an essential ingredient of the CL macro system.

samth

unread,
Dec 8, 2006, 10:21:59 AM12/8/06
to

Pascal Costanza wrote:
> Rob Warnock wrote:
> > Pascal Costanza <p...@p-cos.net> wrote:
> > +---------------
> > | min...@gmail.com wrote:
> > | > In terms of expressive power, are they equal (in their own language)?
> > | > and do they have any difference?
> > |
> > | The default macro system of R5RS Scheme is more restricted than Common
> > | Lisp's macro system, but Scheme' syntax-case (which is going to be part
> > | of R6RS) is more or less on par wrt expressive power.
> > +---------------
> >
> > Plus, many [most?] Scheme implementations provide
> > CL-style "defmacro" (or equivalent) as an extension.
>
> An important ingredient of the Common Lisp macro system is the
> &environment parameter that allows you to reason about the lexical
> environment in which a macro is expanded. This seems to be typically
> missing in Scheme versions of CL-style macros and makes a big difference
> wrt expressiveness.
>
> macroexpand-1 and macroexpand are also important elements of the CL
> macro system.

I'm curious about how the &environment parameter is typically used.
For example, according to the hyperspec, it seems that these lexical
environments are used for looking up the functions bound to macro
names, and as the environment to macroexpand[-1].

In PLT Scheme, similar features are available ([1], [2]), but they rely
on the implicit syntactic environment. Is the fact that environments
are first-class values typically used in CL, or is the current
environment always the one supplied?

In other words, could these CL macros that you describe (of which I'd
like to see examples) be ported to PLT Scheme's primitives?

[1]
http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3100
[2]
http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3124

Thanks,

sam th

Abdulaziz Ghuloum

unread,
Dec 8, 2006, 10:26:03 AM12/8/06
to

Pascal Bourguignon wrote:
> Perhaps "theorical expressiveness". What I constat (but I'm no scheme
> specialist), is that I write clearer and shorter macros in CL than in
> scheme. ...

Yes. The scheme macros *you* write are neither clear nor short (at
least the ones I read in c.l.s., which are sometimes also incorrect).
I agree, you are no scheme specialist. What does that say about your
optinion w.r.t. the expressive power of the two systems?

Aziz,,,

samth

unread,
Dec 8, 2006, 10:28:52 AM12/8/06
to

Pascal Costanza wrote:
> samth wrote:
> > Further, in the sense of Felleisen's "On the Expressive Power of
> > Programming Languages", adding gensym is not a macro-expressible (in
> > the technical sense of that paper) transformation, and thus the
> > capacity for hygiene also gives more expressiveness to
> > syntax-{rules,case} macros.
>
> I don't get what you want to say here. Could you elaborate?

A new construct is "macro-expressible" if it could be defined as an
arbitrary macro, roughly. This requires that multiple uses of the new
construct not have to communicate with each other, since then the
transformation is global, not local. The addition of the counter for
gensym is a global, not a local transformation (since we have to define
the counter variable before the first macro definition, roughly).

If we take gensym as a part of the original system, then this concern
doesn't apply.

sam th

Pascal Bourguignon

unread,
Dec 8, 2006, 11:10:45 AM12/8/06
to
"Abdulaziz Ghuloum" <aghu...@gmail.com> writes:

Exactly. You have to factor the programmer in the expressivity equation.

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

IMPORTANT NOTICE TO PURCHASERS: The entire physical universe,
including this product, may one day collapse back into an
infinitesimally small space. Should another universe subsequently
re-emerge, the existence of this product in that universe cannot be
guaranteed.

Rob Thorpe

unread,
Dec 8, 2006, 12:38:23 PM12/8/06
to
min...@gmail.com wrote:
> In terms of expressive power, are they equal (in their own language)?
> and do they have any difference?

I'll leave that to the professionals...

> BTW, which Lisp/Scheme compiler implementation produce the fastest
> executable (x86, Linux)?

>From my (limited) experience SBCL & CMUCL are the fastest, and there is
little between them. ECL & GCL are fairly close behind. CLisp is very
fast for an interpreter, but it is not as fast as the others I've
mentioned, which are compilers.

Some commercial implementations are fast too, but I don't know about
those.

j...@codeartist.org

unread,
Dec 8, 2006, 3:01:22 PM12/8/06
to

samth schrieb:

> A new construct is "macro-expressible" if it could be defined as an
> arbitrary macro, roughly. This requires that multiple uses of the new
> construct not have to communicate with each other, since then the
> transformation is global, not local. The addition of the counter for
> gensym is a global, not a local transformation (since we have to define
> the counter variable before the first macro definition, roughly).
>
> If we take gensym as a part of the original system, then this concern
> doesn't apply.

I think I don't get it too...
The counter in a gensym constructed symbol is not responsible to make
it unique.
Symbols created by gensym are uninterned - the name could be equal they
are still
different symbols. So what should the counter of a gensym have to do
with expressive power?

ciao,
Jochen

samth

unread,
Dec 8, 2006, 3:49:18 PM12/8/06
to

It's true that in real implementations, the non-eq?ness of gensym'd
symbols is based on a symbol table rather than the counter used in the
names of the symbols. However, the symbol table is a piece of global
state, just like the counter.

The basic idea is that using global state is not a local
transformation.

If you want more information on this, you should look at the original
paper.
http://www.ccs.neu.edu/scheme/pubs/scp91-felleisen.ps.gz

sam th

samth

unread,
Dec 8, 2006, 3:52:13 PM12/8/06
to

Pascal Costanza wrote:
> samth wrote:
> > Pascal Costanza wrote:
> >> min...@gmail.com wrote:
> >>> In terms of expressive power, are they equal (in their own language)?
> >>> and do they have any difference?
> >> The default macro system of R5RS Scheme is more restricted than Common
> >> Lisp's macro system, but Scheme' syntax-case (which is going to be part
> >> of R6RS) is more or less on par wrt expressive power.
> >
> > This isn't quite correct - because of referential transparency, CL
> > macros cannot replicate the behavior of syntax-rules or syntax-case
> > macros. Therefore, CL macros are incomparable with syntax-rules.
>
> That's incorrect. Paul Graham shows in "On Lisp" a number of techniques
> how to do this manually, and they are straightforward and require only
> local changes to your source code. It's also possible to embed an
> extension in CL that adds semi-automatic referential transparency in a
> portable way. (I have an implementation, and plan to report on this.)

Can you cite the part of On Lisp you are referring to? In the copy I
downloaded from the website, the only advice given for avoiding
referential transparency problems is to give global variables names
with * at the beginning and end (which is obviously not a universal
solution, or a local change).

sam th

Pascal Costanza

unread,
Dec 8, 2006, 4:41:24 PM12/8/06
to

The typical use is for code walkers.

> In PLT Scheme, similar features are available ([1], [2]), but they rely
> on the implicit syntactic environment. Is the fact that environments
> are first-class values typically used in CL, or is the current
> environment always the one supplied?

I guess in most cases, it's the one that is supplied. (But, of course,
the only thing I can say for sure about 95% of the cases is that I
haven't seen them... ;)

> In other words, could these CL macros that you describe (of which I'd
> like to see examples) be ported to PLT Scheme's primitives?
>
> [1]
> http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3100
> [2]
> http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3124

I find the descriptions at these links hard to understand without more
context (and I currently don't have the time to study this in more
detail), but indeed sounds like they provide that functionality.

Pascal Costanza

unread,
Dec 8, 2006, 4:44:40 PM12/8/06
to
samth wrote:
> Pascal Costanza wrote:
>> samth wrote:
>>> Further, in the sense of Felleisen's "On the Expressive Power of
>>> Programming Languages", adding gensym is not a macro-expressible (in
>>> the technical sense of that paper) transformation, and thus the
>>> capacity for hygiene also gives more expressiveness to
>>> syntax-{rules,case} macros.
>> I don't get what you want to say here. Could you elaborate?
>
> A new construct is "macro-expressible" if it could be defined as an
> arbitrary macro, roughly. This requires that multiple uses of the new
> construct not have to communicate with each other, since then the
> transformation is global, not local. The addition of the counter for
> gensym is a global, not a local transformation (since we have to define
> the counter variable before the first macro definition, roughly).

OK, I see.

> If we take gensym as a part of the original system, then this concern
> doesn't apply.

That's what I meant with my second response. A CL-style macro system
without something like gensym would indeed be pretty unreliable. But
macros provide a way to transform s-expressions, and symbols together
with the fact that their eq-ness can be relied upon are an essential
ingredient of s-expressions (in Common Lisp).

Jens Axel Søgaard

unread,
Dec 8, 2006, 5:02:13 PM12/8/06
to
samth skrev:

This thread revolved around some of the same issues.

<http://groups.google.com/group/comp.lang.lisp/msg/7893ba79443a82f8?hl=en&>

In particular Pascal C and I got to the conclusion that it is
non-trivial to make CL macros referential transparent, but that instead
CL offer solutions involving packages.

See in particular message 83 to 86, but the entire thread is worth
a read.

--
Jens Axel Søgaard

Eli Barzilay

unread,
Dec 8, 2006, 5:32:02 PM12/8/06
to
Pascal Costanza <p...@p-cos.net> writes:

> That's what I meant with my second response. A CL-style macro system
> without something like gensym would indeed be pretty unreliable. But
> macros provide a way to transform s-expressions, and symbols
> together with the fact that their eq-ness can be relied upon are an
> essential ingredient of s-expressions (in Common Lisp).

There are other important parts in the CL-style macro system that are
required to avoid unreliable macros. One is the need to load files in
a particular order. Another is the requirement to not modify any
builtins. Also there's the general trust in the programmer thing --
it's easy to shoot your feet, but you're expected to avoid doing that.
(Personally, I don't like shooting anybody's feets including mine, but
every once in a while I do like to play around with my feet and see
what happens if I turn them to extra hands or if I rewire them to my
head -- things that are just not possible in CL.)

--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!

samth

unread,
Dec 8, 2006, 5:47:07 PM12/8/06
to

What do you mean here? What code is being walked, and why do you need
an environment? Are you walking expanded code?

> > In PLT Scheme, similar features are available ([1], [2]), but they rely
> > on the implicit syntactic environment. Is the fact that environments
> > are first-class values typically used in CL, or is the current
> > environment always the one supplied?
>
> I guess in most cases, it's the one that is supplied. (But, of course,
> the only thing I can say for sure about 95% of the cases is that I
> haven't seen them... ;)

Do you have any examples? I'm genuinely curious.

> > In other words, could these CL macros that you describe (of which I'd
> > like to see examples) be ported to PLT Scheme's primitives?
> >
> > [1]
> > http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3100
> > [2]
> > http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3124
>
> I find the descriptions at these links hard to understand without more
> context (and I currently don't have the time to study this in more
> detail), but indeed sounds like they provide that functionality.

Basically, syntax-local-value is similar to macro-function (but more
general, in that it can return any value, not just a function), and
local-expand is like macroexpand (but also more general, since it can
be instructed not to expand some macros).

sam th

Pascal Costanza

unread,
Dec 8, 2006, 5:48:35 PM12/8/06
to
Eli Barzilay wrote:
> Pascal Costanza <p...@p-cos.net> writes:
>
>> That's what I meant with my second response. A CL-style macro system
>> without something like gensym would indeed be pretty unreliable. But
>> macros provide a way to transform s-expressions, and symbols
>> together with the fact that their eq-ness can be relied upon are an
>> essential ingredient of s-expressions (in Common Lisp).
>
> There are other important parts in the CL-style macro system that are
> required to avoid unreliable macros.

I mentioned a necessary condition, not a sufficient one. ;)

> One is the need to load files in a particular order.

Same in Scheme. (And both in Scheme and Common Lisp, there are ways to
automate this.)

> Another is the requirement to not modify any
> builtins. Also there's the general trust in the programmer thing --
> it's easy to shoot your feet, but you're expected to avoid doing that.
> (Personally, I don't like shooting anybody's feets including mine, but
> every once in a while I do like to play around with my feet and see
> what happens if I turn them to extra hands or if I rewire them to my
> head -- things that are just not possible in CL.)

This is going too fast: What is it that you cannot do in CL?!?

Pascal Costanza

unread,
Dec 8, 2006, 6:00:17 PM12/8/06
to

There are two cases: global macros and local macros.

For global macros, you can use the package system in CL. This is

described in Chapter 9.7 in "On Lisp".

For local macros, the problem is illustrated with the following example:

(let ((x 42))
(macrolet ((foo () '(print x)))
(let ((x 88))
(foo))))

This prints 88, although you might conclude from the first two lines
that what is actually intended here is to print 42.

The solution to this is to just rename the involved variables. This is
all nested code, so is all written by the same programmer. (If parts of
this code are the result of some macroexpansion, that macro can take
care of hygiene.)


It is true that syntax-rules provides stronger guarantees because it
automatically takes care of referential transparency. (But in turn, this
also complicates other kinds of macros that you might want to express.)

Eli Barzilay

unread,
Dec 8, 2006, 6:06:12 PM12/8/06
to
Pascal Costanza <p...@p-cos.net> writes:

> > One is the need to load files in a particular order.
>
> Same in Scheme. (And both in Scheme and Common Lisp, there are ways
> to automate this.)

No -- at least not in PLT, when you're using the module system. (And
that's an important point about "compilable" as in Matthew's paper.)


> > Another is the requirement to not modify any builtins. Also
> > there's the general trust in the programmer thing -- it's easy to
> > shoot your feet, but you're expected to avoid doing that.
> > (Personally, I don't like shooting anybody's feets including mine,
> > but every once in a while I do like to play around with my feet
> > and see what happens if I turn them to extra hands or if I rewire
> > them to my head -- things that are just not possible in CL.)
>
> This is going too fast: What is it that you cannot do in CL?!?

Here's a quick example:

(module silly-contracts mzscheme
(provide (all-from-except mzscheme define)
(rename contracted-define define))
(define-syntax contracted-define
(syntax-rules (:)
[(contracted-define (f [x : xpred?] ...) : fpred? body ...)
(define (f x ...)
(unless (xpred? x)
(error 'f "wrong value for ~s: ~s" 'x x))
...
(let ([result (begin body ...)])
(if (fpred? result)
result
(error 'f "my code is broken: trying to return ~s" result))))]
[(contracted-define x : pred? val)
(define x
(let ([v val])
(if (pred? v)
v
(error 'x "broken definition: trying to bind to ~s" v))))]
[(contracted-define . whatever)
(define . whatever)])))

which can be used to replace your `define' -- but still keeping your
sanity. Note that each use of the new `contracted-define' uses the
built in `define', and also note that programmers that use this code
still use a plain `define', which is really my `contracted-define',
which is really expanding to the built in `define'.

So, in the context of code that uses the above, my left leg is rewired
to stick out of my forehead, but I can still walk. In CL I'm just not
allowed to touch it.

Pascal Costanza

unread,
Dec 8, 2006, 6:23:56 PM12/8/06
to
samth wrote:
> Pascal Costanza wrote:
>> samth wrote:
>>> I'm curious about how the &environment parameter is typically used.
>>> For example, according to the hyperspec, it seems that these lexical
>>> environments are used for looking up the functions bound to macro
>>> names, and as the environment to macroexpand[-1].
>> The typical use is for code walkers.
>
> What do you mean here? What code is being walked, and why do you need
> an environment? Are you walking expanded code?

Assume you have a macro definition that gets passed some code, and you
want to know more details about that code, for example to optimize the
expansion. The basic approach is to use macroexpand and analyse the
expanded code, roughly like this:

(defmacro m (... &body body &environment env)
(let ((local-expansion (macroexpand body env)))
...))

That's the very rough idea. See http://bc.tech.coop/blog/040512.html for
a few pointers.

Basically, you can use this to implement macros like the ones presented
in Dan Friedman's "Object-oriented Style".

>>> In PLT Scheme, similar features are available ([1], [2]), but they rely
>>> on the implicit syntactic environment. Is the fact that environments
>>> are first-class values typically used in CL, or is the current
>>> environment always the one supplied?
>> I guess in most cases, it's the one that is supplied. (But, of course,
>> the only thing I can say for sure about 95% of the cases is that I
>> haven't seen them... ;)
>
> Do you have any examples? I'm genuinely curious.

The example using symbol-macrolet provided at
http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm is
pretty interesting. It shows one way how the underspecified compiler-let
from pre-ANSI Common Lisp can better be expressed in terms of symbol-macros.

>>> In other words, could these CL macros that you describe (of which I'd
>>> like to see examples) be ported to PLT Scheme's primitives?
>>>
>>> [1]
>>> http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3100
>>> [2]
>>> http://pre.plt-scheme.org/docs/html/mzscheme/mzscheme-Z-H-12.html#node_idx_3124
>> I find the descriptions at these links hard to understand without more
>> context (and I currently don't have the time to study this in more
>> detail), but indeed sounds like they provide that functionality.
>
> Basically, syntax-local-value is similar to macro-function (but more
> general, in that it can return any value, not just a function), and
> local-expand is like macroexpand (but also more general, since it can
> be instructed not to expand some macros).

OK, so I think the equivalents in Common Lisp are macroexpand on symbol
macros, which can also return any values, not just s-expressions, and
combinations of macroexpand-1 and macroexpand which also allow you to
selectively expand code.

Pascal Costanza

unread,
Dec 8, 2006, 6:51:57 PM12/8/06
to
Eli Barzilay wrote:
> Pascal Costanza <p...@p-cos.net> writes:
>
>>> One is the need to load files in a particular order.
>> Same in Scheme. (And both in Scheme and Common Lisp, there are ways
>> to automate this.)
>
> No -- at least not in PLT, when you're using the module system. (And
> that's an important point about "compilable" as in Matthew's paper.)

The module system in PLT _is_ a way to automate the loading of files in
a particular order.

For these purposes, Common Lispers use system definition facilities. The
only difference is that in the PLT Scheme module system, the
dependencies between modules are defined locally in the module
definitions, whereas in system definition facilities, the dependencies
are (declaratively!) defined outside of the respective files. These two
different ways just have different trade offs.

(For example, one advantage of system definition facilities like
mk-defsystem or asdf is that they work portably across different Common
Lisp implementations.)

Of course, and this is even a very straightforward exercise!

(defpackage :silly-contracts
(:use :common-lisp)
(:shadow :defun :defvar)
(:export :defun :defvar))

(in-package :silly-contracts)

(defmacro defun (name fpred (&rest args) &body body)
`(common-lisp:defun ,name ,(mapcar #'first args)
,@(loop for (x xpred) in args
collect `(assert (,xpred ,x)))
(let ((result (progn ,@body)))
(assert (,fpred result))
result)))

(defmacro defvar (name pred form)
`(common-lisp:defvar ,name
(let ((value ,form))
(assert (,pred value))
value)))

(defpackage :silly-contracts-user
(:use :common-lisp)
(:shadowing-import-from :silly-contracts :defun :defvar))

(in-package :silly-contracts-user)

SILLY-CONTRACTS-USER[7]> (defun foo oddp ((x evenp)) (1+ x))
FOO
SILLY-CONTRACTS-USER[8]> (foo 4)
5
SILLY-CONTRACTS-USER[9]> (foo 5)

*** - (EVENP X) must evaluate to a non-NIL value.
The following restarts are available:
CONTINUE :R1 Retry
ABORT :R2 ABORT
Break 1 SILLY-CONTRACTS-USER[10]> ^D
SILLY-CONTRACTS-USER[11]> (defvar x evenp 4)
X
SILLY-CONTRACTS-USER[12]> (defvar y evenp 5)

*** - (EVENP SILLY-CONTRACTS::VALUE) must evaluate to a non-NIL value.
The following restarts are available:
CONTINUE :R1 Retry
ABORT :R2 ABORT

Better error messages are left as an exercise to the reader. ;)

Again, this is all perfectly portable ANSI Common Lisp.

Eli Barzilay

unread,
Dec 8, 2006, 7:09:59 PM12/8/06
to
(I'll try to make this short, since we're getting to the diminishing
returns zone.)


Pascal Costanza <p...@p-cos.net> writes:

> The module system in PLT _is_ a way to automate the loading of files
> in a particular order.

That's a gross understatement, IMO.


> For these purposes, Common Lispers use system definition
> facilities. The only difference is that in the PLT Scheme module
> system, the dependencies between modules are defined locally in the
> module definitions, whereas in system definition facilities, the
> dependencies are (declaratively!) defined outside of the respective
> files. These two different ways just have different trade offs.

Modules are compilation units -- taking a global-namespace facility
and slapping a loader-sequencing tool doesn't make change things much,
you still deal with a global REPL with its problems.


> (For example, one advantage of system definition facilities like
> mk-defsystem or asdf is that they work portably across different
> Common Lisp implementations.)

(Obviously, the PLT module system is portable across different PLT
implementations, but I'd guess that you want to go down that road as
much as I do.)


> Of course, and this is even a very straightforward exercise!

> [...]

And you're still limited to namespace control. (My personal
experience is that when you start writing code that deals with both
packages things get ugly fast. But I won't quibble more.)

Pascal Costanza

unread,
Dec 8, 2006, 7:43:47 PM12/8/06
to
Eli Barzilay wrote:
> (I'll try to make this short, since we're getting to the diminishing
> returns zone.)
>
> Pascal Costanza <p...@p-cos.net> writes:
>
>> The module system in PLT _is_ a way to automate the loading of files
>> in a particular order.
>
> That's a gross understatement, IMO.
>
>> For these purposes, Common Lispers use system definition
>> facilities. The only difference is that in the PLT Scheme module
>> system, the dependencies between modules are defined locally in the
>> module definitions, whereas in system definition facilities, the
>> dependencies are (declaratively!) defined outside of the respective
>> files. These two different ways just have different trade offs.
>
> Modules are compilation units -- taking a global-namespace facility
> and slapping a loader-sequencing tool doesn't make change things much,
> you still deal with a global REPL with its problems.

The pros and cons of modules vs packages weren't under discussion. The
system definition facilities for Common Lisp do solve the issue of
loading definitions in the right order. If you care about only that
problem, then these two solutions are on par.

>> Of course, and this is even a very straightforward exercise!
>> [...]
>
> And you're still limited to namespace control. (My personal
> experience is that when you start writing code that deals with both
> packages things get ugly fast. But I won't quibble more.)

That's quite a different statement from your original "just not possible
in CL" claim. Personal experiences can vary...

Eli Barzilay

unread,
Dec 8, 2006, 7:52:30 PM12/8/06
to
Pascal Costanza <p...@p-cos.net> writes:

> That's quite a different statement from your original "just not
> possible in CL" claim. Personal experiences can vary...

[Going back to the point that Sam made: the namespace solution is a
global change to the code.]

vedm

unread,
Dec 8, 2006, 8:27:45 PM12/8/06
to
Eli Barzilay <e...@barzilay.org> writes:

> Pascal Costanza <p...@p-cos.net> writes:
>
>> That's quite a different statement from your original "just not
>> possible in CL" claim. Personal experiences can vary...
>
> [Going back to the point that Sam made: the namespace solution is a
> global change to the code.]

this doesn't make your "just not possible in CL" claim less glaringly
wrong.


--
vedm

Eli Barzilay

unread,
Dec 8, 2006, 11:21:31 PM12/8/06
to
vedm <n...@ns.com> writes:

Neither less, nor more. Of course. You could even look at my
original code:

(module silly-contracts mzscheme
(provide (all-from-except mzscheme define)
(rename contracted-define define))
(define-syntax contracted-define

[...]))

and remove all of module-related stuff:

(define-syntax contracted-define
[...])

The result works just as fine -- as long as you use
`contracted-define' in code that wants to use this. If you're fine
with that (or with a facility that will twist the current input so
`define' is used as `define-contract'), then not only was I wrong, but
there is no use for modules at all. If you go down the
"TM-equivalent" path, then what you usually get is a flamewar that
goes nowhere -- and one of the major lessons of the expressiveness
paper is that TM-equivalence is as bogus as it is.

Alex Shinn

unread,
Dec 9, 2006, 3:19:40 AM12/9/06
to
min...@gmail.com wrote:
> In terms of expressive power, are they equal (in their own language)?
> and do they have any difference?

Broadly speaking, you can categorize macros along two aspects:
low-level vs. high-level, and hygienic vs. unhygienic. The following
chart shows some examples of all four resulting combinations:


Unhygienic Hygienic
----------------------------------
Low-level: CL's defmacro syntactic closures
(computed) explicit renaming
----------------------------------
High-level: C's #define syntax-rules
(templated)
----------------------------------


Note: SYNTAX-CASE is a hygienic macro system that lets you mix
low-level and high-level styles. Implementations with low-level
hygienic macros typically build SYNTAX-RULES on top of them.

Low-level macros allow you the full use of the host language, whereas
high-level macros typically rely on some form of pattern matching and
template substitution. Not all template systems are equal - I
included C's #define in the chart for completeness, but it is nowhere
near as expressive as other systems such as the R5RS SYNTAX-RULES.
#define macros take a single template of a fixed number of arguments.
C99 macros at least can be variadic, but they are still so limited
it's not worth discussing them in the context of any Lisp macro
system.

SYNTAX-RULES macros, on the other hand, can do a powerful form of
pattern matching on their arguments. For many uses, including all of
the derived forms of R5RS, they are almost optimally clear and
succinct. For example, LET, which is just syntactic sugar for
LAMBDA, could be defined as follows:

(define-syntax let
(syntax-rules ()
((let ((variable value) ...) ; template
body ...)
((lambda (variable ...) ; substitution
body ...)
value ...))))

Ignore the define-syntax, syntax-rules and parens, and just look at
the template, and the resulting substitution. The `...' means to
match 0 or more instances of the preceding pattern. Thus we have a
template of 0 or more (variable value) bindings in our LET, and we
replace it with a LAMBDA of those variable names applied to the
values.

You can have multiple patterns in SYNTAX-RULES, and the first one
that matches is expanded, thus providing a Turing-complete
template-oriented language. If you get used to a style of
programming called CPS (continuation-passing style), you can then use
this to implement macros of moderate complexity without much effort.
People keep on coming up with new tricks in SYNTAX-RULES and new
examples of what it can do, to the extent that you can program an
entire Scheme interpreter in it, but such macros are not practical.
There comes a point at which low-level macros are better suited for
the job (where that point lies is a matter of debate).

Macro hygiene is a little more complicated, but the basic idea is
that macros shouldn't break unexpectedly because of variable names or
the way they are composed. The following page explains the problems
hygiene solves:

http://community.schemewiki.org/?hygiene-versus-gensym

The NAIVE-SWAP! on that page shows pretty clearly what you want to
do, but is broken. To make the macro iron-clad, you need to go
through all the work that the explicit renaming macro HYGIENIC-SWAP!
is doing. This is a nice example because it shows you at a low level
what goes into maintaining hygiene. For comparison, the SYNTAX-RULES
version would just be

(define-syntax swap!
(syntax-rules ()
((swap! a b)
(let ((value a))
(set! a b)
(set! b value)))))

which is even clearer than the original NAIVE-SWAP! and does all the
same hygiene work as HYGIENIC-SWAP! automatically.

Now, lack of hygiene in your macros is not the end of the world. You
just need to follow some rules to minimize problems:

1) always use gensyms for inserted symbols
2) never redefine any standard procedures
3) pay attention to namespaces and load order

This is a perfectly acceptable model of development and works fine
for Common-Lispers. Schemers, because they have hygiene guarantees,
are more likely to ignore these rules and compose increasingly
complicated macros until they've redefined their language. This can
be useful for creating domain-specific languages for a particular
problem.

[Beware, though, that you pretty much can never mix hygienic macros
with unhygienic macros, even though most Scheme implementations
provide both. The hygienic macros will rename symbols, while the
unhygienic macros won't, which can quickly result in mismatches.]

The one thing you've seen mentioned from other posters that CL has
that none of the Scheme macros do is the optional &environment
argument. This is very limited, referring only to other macros in
the environment, not variables or functions, and thus cannot be used
for hygiene. What it can be used for is MACROEXPAND. The reason you
might want to use MACROEXPAND inside a macro is to simplify the body
of a macro to then perform some further analysis or manipulation of
it. This is called a code-walking macro. They are generally fragile
and discouraged, but can do some impressive things.

To get back to your question, it would depend on which of Scheme's
macro systems you're referring to, but any of the low-level hygienic
systems are pretty much pure supersets of defmacro's power, so long
as they provide the equivalent of MACROEXPAND (which to my knowledge
all of them do). Without MACROEXPAND, you'd have to choose between
that and hygiene.

--
Alex

Pascal Costanza

unread,
Dec 9, 2006, 4:11:13 AM12/9/06
to
Eli Barzilay wrote:
> Pascal Costanza <p...@p-cos.net> writes:
>
>> That's quite a different statement from your original "just not
>> possible in CL" claim. Personal experiences can vary...
>
> [Going back to the point that Sam made: the namespace solution is a
> global change to the code.]

So what?

Marcus Breiing

unread,
Dec 9, 2006, 4:18:05 AM12/9/06
to
"samth" <sam...@gmail.com> writes:

> [..] because of referential transparency, CL macros cannot replicate


> the behavior of syntax-rules or syntax-case macros.

That's possibly true for strict ANSI-CL, which dropped the environment
access facilities of CLTL2. Allowing full environment access, I
suspect that you actually could locally transform (sensu Felleisen)
hygienic macros into equivalent CL macros. But I haven't tried.

> Further, in the sense of Felleisen's "On the Expressive Power of
> Programming Languages", adding gensym is not a macro-expressible (in
> the technical sense of that paper) transformation

Thus (sensu Felleisen and ceteris paribus) a language with gensym is
strictly more expressive than one without.

Well ... q.e.d. :-)

--
Marcus Breiing
(Cologne, Germany)

Pascal Costanza

unread,
Dec 9, 2006, 4:24:00 AM12/9/06
to

The TM-equivalence argument is nonsense here. It's absolutely possible
to "redefine" standard Common Lisp definitions for your own programs.
It's not only possible, but also routine to do so. I am using this in my
own projects, and have seen this in quite a few others as well. Common
Lispers don't seem to have serious problems with this.

It's true that the features that we have discussed in our subthread are
tied to the PLT module system, and that Common Lisp misses some other
features of such an advanced module system. But the specific things you
claimed are impossible in CL are definitely possible, straightforwardly
so, and used in practice.

See also http://www.research.att.com/~bs/bs_faq.html#compare

Pascal Costanza

unread,
Dec 9, 2006, 5:52:16 AM12/9/06
to
Eli Barzilay wrote:

>>> Another is the requirement to not modify any builtins. Also
>>> there's the general trust in the programmer thing -- it's easy to
>>> shoot your feet, but you're expected to avoid doing that.
>>> (Personally, I don't like shooting anybody's feets including mine,
>>> but every once in a while I do like to play around with my feet
>>> and see what happens if I turn them to extra hands or if I rewire
>>> them to my head -- things that are just not possible in CL.)
>> This is going too fast: What is it that you cannot do in CL?!?
>
> Here's a quick example:

[...]

...which I still think is invalid. However, I recall that the PLT module
system allows you to redefine function application within a module (by
overriding some internal apply operator). That's something that's indeed
not possible in Common Lisp, and would have been handy in some of my
language extension experiments.

samth

unread,
Dec 9, 2006, 9:26:50 AM12/9/06
to

Marcus Breiing wrote:
> "samth" <sam...@gmail.com> writes:
>
> > [..] because of referential transparency, CL macros cannot replicate
> > the behavior of syntax-rules or syntax-case macros.
>
> That's possibly true for strict ANSI-CL, which dropped the environment
> access facilities of CLTL2. Allowing full environment access, I
> suspect that you actually could locally transform (sensu Felleisen)
> hygienic macros into equivalent CL macros. But I haven't tried.

I doubt that referential transparency can be accomplished with a local
transformation.

> > Further, in the sense of Felleisen's "On the Expressive Power of
> > Programming Languages", adding gensym is not a macro-expressible (in
> > the technical sense of that paper) transformation
>
> Thus (sensu Felleisen and ceteris paribus) a language with gensym is
> strictly more expressive than one without.

Yes. Whether a macro system with gensym is more expressive than one
with just, say, syntax-case is a harder problem.

sam th

Eli Barzilay

unread,
Dec 9, 2006, 11:03:37 AM12/9/06
to
Pascal Costanza <p...@p-cos.net> writes:

> The TM-equivalence argument is nonsense here. It's absolutely
> possible to "redefine" standard Common Lisp definitions for your own
> programs. It's not only possible, but also routine to do so. I am
> using this in my own projects, and have seen this in quite a few
> others as well.

If you're willing to accept certain global modifications to your code
then you won't see a problem. In your example, that would be the use
of `common-lisp:defun' and `common-lisp:defvar' (the explicit package
qualification). (And this is the same thing that happens in
TM-dead-threads.)


> Common Lispers don't seem to have serious problems with this.

[Well, my example failed to point at the problems that you get when
you try to wire up packages in more complex ways. Not surprising,
given that it was only a limited toy.]


> See also http://www.research.att.com/~bs/bs_faq.html#compare

[I certainly don't want to make this thread longer than it is.
Returns have diminished away to zero.]


Pascal Costanza <p...@p-cos.net> writes:

> ...which I still think is invalid. However, I recall that the PLT
> module system allows you to redefine function application within a
> module (by overriding some internal apply operator). That's
> something that's indeed not possible in Common Lisp, and would have
> been handy in some of my language extension experiments.

This facility is tied to the expressiveness point in that it allows to
have a local transformation in cases where you'd usually use a code
walker (as well as other such `special' macros). You could probably
add something similar to CL (except that there is no `#%app' symbol in
the input code, so hooking it to the package-prefix thing will require
some thought) and get similar benefits.

Marcus Breiing

unread,
Dec 9, 2006, 11:35:02 AM12/9/06
to
"samth" <sam...@gmail.com> writes:

> I doubt that referential transparency can be accomplished with a local
> transformation.

Since we're comparing expressiveness of macro systems, "local" refers
to the transformations between macro definitions (here: scheme-style
into defmacro-with-environment-access), _not_ to the transformations
implemented by those macros.

Thomas Hafner

unread,
Dec 9, 2006, 11:53:26 AM12/9/06
to

> If you get used to a style of programming called CPS
> (continuation-passing style), you can then use this to implement
> macros of moderate complexity without much effort.

I'm interested on reading more about that topic. Can you please give
some examples and/or links?

Regards
Thomas

samth

unread,
Dec 9, 2006, 12:53:10 PM12/9/06
to

Exactly. But I still doubt that referential transparency can be so
achieved. That doesn't mean I have a proof that it's impossible, but
in the absence of evidence to the contrary, I'm skeptical.

sam th

Pascal Costanza

unread,
Dec 10, 2006, 10:17:20 AM12/10/06
to
Eli Barzilay wrote:
> Pascal Costanza <p...@p-cos.net> writes:
>
>> The TM-equivalence argument is nonsense here. It's absolutely
>> possible to "redefine" standard Common Lisp definitions for your own
>> programs. It's not only possible, but also routine to do so. I am
>> using this in my own projects, and have seen this in quite a few
>> others as well.
>
> If you're willing to accept certain global modifications to your code
> then you won't see a problem. In your example, that would be the use
> of `common-lisp:defun' and `common-lisp:defvar' (the explicit package
> qualification). (And this is the same thing that happens in
> TM-dead-threads.)

I am not following you. What is it that you are referring to when you
say "global modifications"?

Both in the Common Lisp package system and in the PLT module system,
there is only one entity that you can refer to with one name. If you
want to have two defun versions, at least one of them has to be
qualified in Common Lisp. If want to have two define versions, at least
one of them has to be renamed in PLT. What's the big difference here?

Both CL packages and PLT modules allow you to create local "worlds" with
different language definitions. PLT modules "just" provide stronger
encapsulation guarantees.

>> Common Lispers don't seem to have serious problems with this.
>
> [Well, my example failed to point at the problems that you get when
> you try to wire up packages in more complex ways. Not surprising,
> given that it was only a limited toy.]

Can you give an example in which packages fail?

>> See also http://www.research.att.com/~bs/bs_faq.html#compare
>
> [I certainly don't want to make this thread longer than it is.
> Returns have diminished away to zero.]

What do you suggest to increase the potential returns?

Pascal Costanza

unread,
Dec 10, 2006, 11:03:01 AM12/10/06
to

It's important to see this in the context of the common practice in the
language under discussion.

As I already tried to explain elsewhere in this thread, there are two
cases, global macros and local macros. With global macros, you do the
following in Common Lisp:

(defun some-auxiliary-function (...)
;; You don't want this to interfere with other code
...)

(defmacro some-macro (...)
;; This expands to an invocation of some-auxiliary-function
`(... (some-auxiliary-function ...) ...))

To ensure that in expansions, there will not be any conflicts here, the
following steps are sufficient to ensure "referential transparency":

- Use a good and descriptive name for the auxiliary function.
(Admittedly, this doesn't ensure anything, but helps a lot.)

- Put both definitions in a package, and export some-macro but not
some-auxiliary-function. This ensures that code using some-macro in
other packages won't have any conflicts with some-auxiliary-function.


With local macros, the following or similar cases "hurt":

(let ((x 42))
(macrolet ((foo () 'x))
(let ((x 88))
(+ x (foo)))))

The solution is to just not do this. This your own code, so you have all
the names under control. Write this instead:

(let ((x 42))
(macrolet ((foo () 'x))
(let ((y 88))
(+ y (foo)))))


The one case that indeed seems impossible to achieve is this:

(let ((x 42))
(defmacro foo () 'x))

This creates a global macro foo that expands into 'x, presumably to
refer to the local variable x. This code simply doesn't make sense in
Common Lisp. You would say the following instead:

(defvar *x* 42)

(defmacro foo () '*x*)

...and use packages to ensure hiding the variable name from other code.
We are actually back to the global case here...

William D Clinger

unread,
Dec 10, 2006, 12:27:19 PM12/10/06
to
min...@gmail.com wrote:
> In terms of expressive power, are they equal (in their own language)?
> and do they have any difference?

No, they are not equal. Yes, they have any difference.

> BTW, which Lisp/Scheme compiler implementation produce the fastest
> executable (x86, Linux)?

No one system is fastest on all benchmarks. For the kinds
of programs I write and benchmark, Chez Scheme is often
the fastest.

Will

samth

unread,
Dec 10, 2006, 6:49:32 PM12/10/06
to

Pascal Costanza wrote:
> samth wrote:
> > Marcus Breiing wrote:
> >> "samth" <sam...@gmail.com> writes:
> >>
> >>> I doubt that referential transparency can be accomplished with a local
> >>> transformation.
> >> Since we're comparing expressiveness of macro systems, "local" refers
> >> to the transformations between macro definitions (here: scheme-style
> >> into defmacro-with-environment-access), _not_ to the transformations
> >> implemented by those macros.
> >
> > Exactly. But I still doubt that referential transparency can be so
> > achieved. That doesn't mean I have a proof that it's impossible, but
> > in the absence of evidence to the contrary, I'm skeptical.
>
> It's important to see this in the context of the common practice in the
> language under discussion.

[snip a long discussion about how to name your variables]

That was a very comprehensive survey about how to name your variables
and use packages to avoid referential transparency issues. However, in
the example you gave:

(let ((x 42))
(macrolet ((foo () 'x))
(let ((x 88))
(+ x (foo)))))

There is nothing you can change the body of the `foo' macro to that
causes the result to be 130, *without changing the rest of the
example*. That's what not having referential transparency means. By
contrast, with Scheme macros, the result is always 130, regardless of
the naming of the variable.

I realize this property may not be important to you, and you may think
the effort required to avoid this issue is worth it for a "simpler"
macro system. But defmacro macros are not referentially transparent.

sam th

Alex Shinn

unread,
Dec 11, 2006, 12:54:08 AM12/11/06
to
Thomas Hafner writes:

Many of the SRFI reference implementations, being restricted
to portable R5RS, serve as an example of this technique. In
particular, SRFI-53 (http://srfi.schemers.org/srfi-53/) builds an
entire framework for working with CPS macros (it was withdrawn
because it makes it too easy to write macros which are
unacceptably inefficient).

There are also two syntax-rules primers:

For the insane:

http://groups.google.com/group/comp.lang.scheme/msg/eb6cc6e11775b619
For the merely eccentric:
http://home.comcast.net/~prunesquallor/macro.txt

Scheme compilers often perform a CPS transformation on their source
to work with a simpler language. I like the explanation given in
David A. Kranz's Orbit thesis:

http://repository.readscheme.org/ftp/papers/orbit-thesis.ps.gz

--
Alex

Abdulaziz Ghuloum

unread,
Dec 11, 2006, 1:17:47 AM12/11/06
to

Pascal Costanza wrote:
> ...

> With local macros, the following or similar cases "hurt":
>
> (let ((x 42))
> (macrolet ((foo () 'x))
> (let ((x 88))
> (+ x (foo)))))
>
> The solution is to just not do this. This your own code, so you have all
> the names under control. Write this instead:
>
> (let ((x 42))
> (macrolet ((foo () 'x))
> (let ((y 88))
> (+ y (foo)))))

Let's leave macros aside for a minute and rewrite the first program
using boring code only:

(let ((x 42))
(flet ((foo () x))


(let ((x 88))
(+ x (foo)))))

We both agree, I presume, that the correct value of this program must
be 130. Emacs-lispers would protest: But we want the answer to be 176!
Emacs-lispers, after all, know that "the solution is to just not do
this." They would gladly show you how to rewrite that example as:

(let ((x 42))
(flet ((foo () x))


(let ((y 88))
(+ y (foo)))))

They might even add: "this is your own code, so you have all the names
under control."

So, Pascal, do you buy this "solution"?

Aziz,,,

Pascal Costanza

unread,
Dec 11, 2006, 2:17:05 AM12/11/06
to

Ah, excellent. This is exactly the question that allows me to make my
point very clear!

In Common Lisp, I can get both results very easily:

(let ((x 42))
(flet ((foo () x))
(let ((x 88))
(+ x (foo)))))

=> 130

(let ((x 42))
(declare (special x))


(flet ((foo () x))
(let ((x 88))

(declare (special x))
(+ x (foo)))))
=> 176


Likewise, I can get both results very easily with CL-style macros:

(let ((x 42))
(macrolet ((foo () 'x))
(let ((y 88))
(+ y (foo)))))

=> 130


(let ((x 42))
(macrolet ((foo () 'x))
(let ((x 88))
(+ x (foo)))))

=> 176


For all four cases, I can imagine situations in which these different
results are respectively the correct results.


With syntax-rules, I can get only one of the possible results, i.e.,
130. I don't see how to make the code return 176, at least not in a
straightforward way. [1]


My original statement in this thread was this:

> The default macro system of R5RS Scheme is more restricted than
> Common Lisp's macro system, but Scheme' syntax-case (which is going
> to be part of R6RS) is more or less on par wrt expressive power.

I regard syntax-rules to be more restricted than CL-style defmacro,
because I can very easily get two reasonable semantics out of CL-style
defmacro, while I can get only one out of syntax-rules.

> The other important question is which one is more convenient to use.
> Of course, you can decide this only for yourself.

...I still stand to both claims.


Pascal


[1] The following "solution" is ruled out for obvious reasons:

(let ((x 42))
(let-syntax ((foo (syntax-rules ()
((foo) x))))
(let ((x 88))
176)))

;-)

Pascal Costanza

unread,
Dec 11, 2006, 2:23:18 AM12/11/06
to

This is all correct.

> I realize this property may not be important to you, and you may think
> the effort required to avoid this issue is worth it for a "simpler"
> macro system. But defmacro macros are not referentially transparent.

This is also correct.

What's important to me in a language construct is first, whether I can
express variations on reasonable semantics or not depending on the
circumstances, and second, whether it is convenient to use, exactly in
this order. I especially distrust preconceived notions of "correctness",
but that's probably just my personal take on such matters.

See my previous response to Aziz for more details.

Reply all
Reply to author
Forward
0 new messages