Macros (Was: Interesting: "Lisp as a competitive advantage")

Jerzy Karczmarczuk karczma@info.unicaen.fr
Fri, 04 May 2001 12:57:29 +0200


Discussion about macros, Lisp, laziness etc. Too many people to cite.
Alan Bawden uses macros to write assertions, and Dylan Thurston comments:

...
> >   (assert (< x 3))
> >
> > Which macro expands into:
> >
> >   (if (not (< x 3))
> >       (assertion-failed '(< x 3)))
> >
> > Where `assertion-failed' is a procedure that generates an appropriate error
> > message.  The problem being solved here is getting the asserted expression
> > into that error message.  I don't see how higher order functions or lazy
> > evaluation could be used to write an `assert' that behaves like this.
> 
> This is a good example, which cannot be implemented in
> Haskell.  "Exception.assert" is built in to the ghc compiler, rather than
> being defined within the language.  On the other hand, the built in
> function gives you the source file and line number rather than the literal
> expression; the macro can't do the former.
> 
> --Dylan Thurston


In general this is not true, look at the macro preprocessing in C. If your
parser is kind enough to yield to the user some pragmatic information about
the read text, say, __LINE etc., you can code that kind of control with
macros as well.

Macros in Scheme are used to unfold n-ary control structures such as COND
into a hierarchy of IFs, etc. Nothing (in principle) to do with laziness
or HO functions. They are used also to define object-oriented layers in
Scheme or Lisp. I used them to emulate curryfied functions in Scheme.

I think that they are less than popular nowadays because they are dangerous,
badly structured, difficult to write "hygienically". Somebody (Erik Meijer?)
asked: "Don't you get dynamic scoping as well with macros?" Well, what is
dynamic here? Surely this is far from "fluid" bindings, this is a good
way to produce name trapping and other diseases.

In Clean there are macros. They are rather infrequently used...

In C++ a whole zone of macro/preprocessor coding began to disappear with
the arrival of inlining, templates, etc.

I think that macros belong to *low-level* languages. Languages where you
feel under the parsing surface the underlying virtual machine. You can
do fabulous things with. My favourite example is the language BALM, many
years before ML, Haskell etc., there was a functional, Lisp-like language
with a more classical, Algol-like syntax, with infix operators, etc.

The language worked on CDC mainframes, under SCOPE/NOS. Its processor was
written in assembler (Compass). But you should have a look on it imple-
mentation! Yes, assembler, nothing more. But this assembler was so macro-
oriented, and so incredibly powerful, that the instructions looked like
Lisp. With recursivity, parentheses, LET forms which allocated registers,
and other completely deliciously crazy constructs. In fact, the authors
used macros to implement the entire Lisp machine, used to process BALM
programs. //Side remark: don't ask me where to find BALM. I tried, I failed.
If *YOU* find it, let me know//

Another place where macros have been used as main horses was the MAINBOL
implementation of Snobol4. But when people started to implement Spitbol
etc. variants of Snobol4, they decided to use more structured, higher-level
approach (there was even an another, portable assembler with higher-level
instructions "embedded"; these avoided the usage of macros).

Jerzy Karczmarczuk
Caen, France