[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Macros and destructuring and functions, oh my!



Sorry, Dan, I beg to differ with you on the philosophical nature of macros.
Macros certainly are functions, of one argument.  They map a piece of
program (a macro call) into another piece of program.  Now, the fact
that macros and functions are invoked by means of the "same syntax"
is sort of a coincidence, and not at all essential.  There is no
reason why lists whose *second* element was an atom beginning with
an upper-case Q could not be reserved to mean macro calls and detected
as such by the evaluator.  Then, in the evaluator, one would have not
	((AND (ATOM (CAR EXP)) (MACROP (FSYMEVAL (CAR EXP))))
	 (EVAL (MACROCALL (FSYMEVAL (CAR EXP)) EXP)))
but instead
	((AND (ATOM (CADR EXP)) (CHAR= #/Q (GETCHAR (CADR EXP) 1))
	 (EVAL (MACROCALL (GET (CADR EXP) 'MACRO) EXP)))
and one could write a quadratic polynomial as (C Q+ (X Q* (B Q+ (X Q* A))))
for example.  Sure, it's not "LISPy", but it's perfectly consistent.
Another, simpler way to detect macro calls would be to require a keyword
like CALL, so instead of (PUSH X Y) we would write (CALL PUSH X Y).

One of the great things about LISP, though, is that the subset of lists
it chooses to reserve to represent macro calls manage to look like function
calls.  This in turn allows the incredibly punnish and gross, but very
efficient, implementation trick of allowing macro definitions to be
stored in the function cell, taking advantage of the fact that the
*particular syntax chosen for macro calls, which confuses them with
function calls*, guarantees that a symbol cannot represent both a function
and a macro simultaneously anyway.

All this flamage is to point out that the only difference between
a function and a macro is when it is invoked, the algorithm for deciding
whether a form is a function call or a macro, and so on.  Once you have
decided to feed arguments to one or the other, it is a simple function.

Now, it is true that in practice up until now destructuring has been the most
useful for macros, which commonly parse apart their arguments into known
fixed pieces.  There is also the fact that ordinary functions in effect
already get one level of destructuring by the fact that they are
considered to get many named arguments rather than a single one (which
is usually a "vector" of some sort); but after all, what are &OPTIONAL
and &REST but destructuring mechanisms?  There is something to be said
for unifying that mechanism with the one used by DEFMACRO and the NIL LET,
provided it can be done without undue clutter.