Python syntax in Lisp and Scheme

Matthias Blume find at my.address.elsewhere
Tue Oct 7 11:39:16 EDT 2003


raffael at mediaone.net (Raffael Cavallaro) writes:

> gregm at cs.uwa.edu.au wrote in message news:<blr1cq$bb1$1 at enyo.uwa.edu.au>...
> > In comp.lang.functional Erann Gat <my-first-name.my-last-name at jpl.nasa.gov> wrote:
> > :> I can't see why a LISP programmer would even want to write a macro.
> > : That's because you are approaching this with a fundamentally flawed
> > : assumption.  Macros are mainly not used to make the syntax prettier
> > : (though they can be used for that).  They are mainly used to add features
> > : to the language that cannot be added as functions.
> > 
> > Really? Turing-completeness and all that... I presume you mean "cannot
> > so easily be added as functions", but even that would surprise me.
> > (Unless you mean cannot be added _to_Lisp_ as functions, because I don't
> > know as much as I'd like to about Lisp's capabilities and limitations.)
> 
> Two words: code duplication.
> 
> Yes, anything that can be done with macros can also be done with
> functions, but if you do it with functions, you will end up with more
> code, and that code will be duplicated in every single source location
> in which that abstraction it utilized.

Three words and a hyphen: Higher-Order Functions.

Most of the things that macros can do can be done with HOFs with just
as little source code duplication as with macros.  (And with macros
only the source code does not get duplicated, the same not being true
for compiled code.  With HOFs even executable code duplication is
often avoided -- depending on compiler technology.)

I say "most" because there are some things that macros can do which
are difficult with HOFs -- but those things have to do with
compile-time calculations.  A good example that was given to me during
the course of a similar discussion here on netnews is that of a
parser-generator macro: it could check at compile time that the input
grammar is, e.g., LL(1).  With HOFs this check would have to happen at
runtime, or at link-time at the earliest.  (Some languages, e.g., SML
can do arbitrary calculations at what we normally call "link time".)

Many static guarantees can be obtained by relying on reasonably
powerful static type systems, but I know of none that is powerful
enough and practical as well as general at the same time which would
be able to check for LL(1)-ness.  That's why macros sometimes "beat"
HOFs.  For most things they don't.

> With a macro, the abstraction is defined once, and the source code
> reflects that abstraction everywhere that abstraction is used
> throughout your program. For large projects this could be hundreds of
> source locations.

Sure.  Same goes for HOFs.

> Without a macro, you have multiple points of maintenance. If your
> abstraction changes, you have to edit scores or hundreds of source
> locations. With a macro, you redefine a single form, in one source
> location, and recompile the dependent code.

All the same with HOFs.

> Finally, there is one thing that macros can do that ordinary functions
> cannot do easily - change the language's rules for functional
> evaluation.

Well, no, not really.  You can define new syntactic forms in terms of
old ones, and the evaluation rules end up being determined by those of
the old ones.  Again, with HOFs you can always get the same
effect -- at the expense of an extra lambda here and there in your
source code.

> This can only be accomplished with functions if you're
> willing to write a set of functions that defer evaluation, by, say
> parsing input, massaging it appropriately, and then passing it to the
> compiler. At that point, however, you've just written your own macro
> system, and invoked Greenspun's 10th Law.

This is false.  Writing your own macro expander is not necessary for
getting the effect.  The only thing that macros give you in this
regard is the ability to hide the lambda-suspensions.  To some people
this is more of a disadvantage than an advantage because, when not
done in a very carefully controlled manner, it ends up obscuring the
logic of the code.  (Yes, yes, yes, now someone will jump in an tell
me that it can make code less obscure by "canning" certain common
idioms.  True, but only when not overdone.)

Matthias




More information about the Python-list mailing list