A DEFMACRO
form looks a lot like a DEFUN
form (see Lesson 7) -- it has a name, a
list of argument names, and a body:
(defmacro name (argument ...) body)
The macro body returns a form to be evaluated. In other words, you need to write the body of the macro such that it returns a form, not a value. When Lisp evaluates a call to your macro, it first evaluates the body of your macro definition, then evaluates the result of the first evaluation. (By way of comparison, a function's body is evaluated to return a value.)
Here are a couple of simple macros to illustrate most of what you need to know:
(defmacro setq-literal (place literal) `(setq ,place ',literal)) SETQ-LITERAL (setq-literal a b) B a B (defmacro reverse-cons (rest first) `(cons ,first ,rest)) REVERSE-CONS (reverse-cons nil A) (B)
SETQ-LITERAL
works like SETQ
, except that
neither argument is evaluated. (Remember that SETQ
evaluates its second argument.) The body of SETQ-LITERAL
has
a form that begins with a `
(pronounced "backquote").
Backquote behaves like quote -- suppressing evaluation of all the enclosed
forms -- except where a comma appears within the backquoted form. A
symbol following the comma is evaluated.
So in our call to (SETQ-LITERAL A B)
above, here's what
happens:
PLACE
to the symbol A
.LITERAL
to the symbol B
.`(SETQ ,PLACE ',LITERAL)
, following
these steps:PLACE
to get the symbol A
.LITERAL
to get the symbol B
.(SETQ A 'B)
.(SETQ A 'B)
.Neither the backquote nor the commas appear in the returned form.
Neither A
nor B
is evaluated in a call to
SETQ-LITERAL
, but for different reasons. A
is
unevaluated because it appears as the first argument of
SETQ
. B
is unevaluated because it appears after
a quote in the form returned by the macro.
The operation of (REVERSE-CONS NIL A)
is similar:
RESTNIL
.
FIRST
to the symbol A
.`(CONS ,FIRST ,REST)
, following these
steps:FIRST
to get the symbol A
.REST
to get the symbol NIL
.(CONS A NIL)
.(CONS A NIL)
.Both arguments of REVERSE-CONS
are evaluated because
CONS
evaluates its arguments, and our macro body doesn't quote
either argument. A
evaluates to the symbol B
, and
NIL
evaluates to itself.
If you want to see how your macro body appears before evaluation, you
can use the MACROEXPAND
function:
(macroexpand '(setq-literal a b)) (SETQ A 'B) (macroexpand '(reverse-cons nil a)) (CONS A NIL)
Since MACROEXPAND
is a function, it evaluates its
arguments. This is why you have to quote the form you want expanded.
The examples in this lesson are deliberately very simple, so you can understand the basic mechanism. In general, macros are trickier to write than functions -- in Chapter 20 we'll look at the reasons and the correct techniques for dealing with more complex situations.