Explanation of macros; Haskell macros

Pascal Costanza costanza at web.de
Mon Nov 3 11:06:09 EST 2003


Joachim Durchholz wrote:

> Is there anything that a macro does that can't be done by preevaluating 
> data structures that contain functions (or closures)? At first glance, 
> I'd say no, but then I don't know what macros are used for in practice.

Macros are mainly used for abstracting away details of sophisticated 
protocols. For me, the "Hello, World" of macro programming is this:

When you want to bind to a resource, you usually have to make sure that 
you also unbind again later on. The standard pattern in many languages, 
modulo syntactic variations, is this:

try: bind resource
      do something
finally: unbind resource


The fact that you need to place the unbind in a finally statement 
reflects the requirement a protocol imposes on the use of rources: You 
have to make sure to execute the necessay steps in a certain order, and 
you have to make sure that certain steps are always executed, no matter 
what. There are lots of examples like this in programming, and 
especially more complicated ones.

A macro allows you to abstract away from this. The same code, in a 
language with macro support, would look like this:

with-bound-resorce:
   do something

The macro "with-bound-resource" takes care of executing the right steps 
at the right time.

Now, this is admittedly not an example for a particularly sophisticated 
protocol. Therefore, one of the usual gut reactions from people who are 
not used to macros yet is "but I can do this with higher order functions!"

However, what this example already shows is: The with-bound-resource 
macro doesn't tell you anything about how it achieves its goals. Yes, 
the natural way to implement this example is with a HOF, but you could 
also use a completely different approach. _With macros you can build 
abstractions that completely hide their implementation details._

This becomes especially useful as soon as your protocols become more 
sophisticated, and you need to insert instructions at arbitrary places 
in the code being passed to a macro, or need to control evaluation of 
the code being passed in some other details.

Because of this high level of expressive power that macros provide, 
Common Lispers use them regularly even for simple things. You can 
effectively write domain-specific abstractions that don't leak, and 
therefore it is justified to use them even for simple protocols.

> Um, well, yes, there is one thing that macros can do: extending syntax 
> in ways that aren't part of the original language syntax. E.g. replacing 
> all those parentheses by indentation, or something similar un-Lispish.
> (Extending syntax in such ways is a mistake IMHO, but YMMV. Anyway, I'm 
> more interested in the question if there's any /semantics/ that can be 
> done via macros but not via compile-time evaluation.)

Compile-time evaluation is a red herring. Macros do their job by 
rewriting abstract syntax trees. (Lisp and macros go very well together 
because in Lisp, you essentially program using a notation that maps 
directly to an internal syntax tree, nearly without any parsing overhead.)

Since the syntax tree is usually available at compile time, that's the 
natural time to let macros do their job. However, in theory it wouldn't 
be a problem to use macro expansion at runtime.

(In Common Lisp, this is already possible in limited ways: an 
interpreted implementation of Common Lisp expands macros during 
evaluation, and when you call EVAL or COMPILE, macros are also expanded 
at runtime. However, you cannot pass macros around as first-class 
objects and APPLY them, at least not in the same way as functions. If 
you wanted to do that the language implementation would need to keep the 
lexical environment information available at runtime.)

> Does anybody have a keyword-style list of useful applications of the 
> macro facilities?

Do you have a keyword-style list of useful applications of functions?


Pascal





More information about the Python-list mailing list