Common Lisp the Language, 2nd Edition
Next: Macro Expansion
Up: Macros
Previous: Macros
The function macro-function
determines whether a given
symbol is the name of a macro. The defmacro
construct
provides a convenient way to define new macros.
[Function]
macro-function
symbol
The argument must be a symbol. If the symbol has a global function
definition that is a macro definition, then the expansion function (a
function of two arguments, the macro-call form and an environment) is
returned. If the symbol has no global function definition, or has a
definition as an ordinary function or as a special form but not as a
macro, then nil
is returned. The function
macroexpand
is the best way to invoke the expansion
function.
It is possible for both macro-function
and
special-form-p
to be true of a symbol. This is possible
because an implementation is permitted to implement any macro also as a
special form for speed. On the other hand, the macro definition must be
available for use by programs that understand only the standard special
forms listed in table 5-1.
macro-function
cannot be used to determine whether a
symbol names a locally defined macro established by
macrolet
; macro-function
can examine only
global definitions.
setf
may be used with macro-function
to
install a macro as a symbol’s global function definition:
(setf (macro-function symbol) fn)
The value installed must be a function that accepts two arguments, an
entire macro call and an environment, and computes the expansion for
that call. Performing this operation causes the symbol to have
only that macro definition as its global function definition;
any previous definition, whether as a macro or as a function, is lost.
It is an error to attempt to redefine the name of a special form.
X3J13 voted in March 1988 (MACRO-FUNCTION-ENVIRONMENT) to add an
optional environment argument to macro-function
.
[Function]
macro-function
symbol
&optional
env
The first argument must be a symbol. If the symbol has a function
definition that is a macro definition, whether a local one established
in the environment env by macrolet
or a global one
established as if by defmacro
, then the expansion function
(a function of two arguments, the macro-call form and an environment) is
returned. If the symbol has no function definition, or has a definition
as an ordinary function or as a special form but not as a macro, then
nil
is returned. The function macroexpand
or
macroexpand-1
is the best way to invoke the expansion
function.
It is possible for both macro-function
and
special-form-p
to be true of a symbol. This is possible
because an implementation is permitted to implement any macro also as a
special form for speed. On the other hand, the macro definition must be
available for use by programs that understand only the standard special
forms listed in table 5-1.
setf
may be used with macro-function
to
install a macro as a symbol’s global function definition:
(setf (macro-function symbol) fn)
The value installed must be a function that accepts two arguments, an
entire macro call and an environment, and computes the expansion for
that call. Performing this operation causes the symbol to have
only that macro definition as its global function definition;
any previous definition, whether as a macro or as a function, is lost.
One cannot use setf
to establish a local macro definition;
it is an error to supply a second argument to
macro-function
when using it with setf
. It is
an error to attempt to redefine the name of a special form.
See also compiler-macro-function
.
[Macro]
defmacro name lambda-list [[ {declaration}* | doc-string ]] {form}*
defmacro
is a macro-defining macro that arranges to
decompose the macro-call form in an elegant and useful way.
defmacro
has essentially the same syntax as
defun
: name is the symbol whose macro definition
we are creating, lambda-list is similar in form to a
lambda-list, and the forms constitute the body of the expander
function. The defmacro
construct arranges to install this
expander function, as the global macro definition of name.
The expander function is effectively defined in the global
environment; lexically scoped entities established outside the
defmacro
form that would ordinarily be lexically apparent
are not visible within the body of the expansion function.
X3J13 voted in March 1989 (DEFINING-MACROS-NON-TOP-LEVEL) to clarify
that, while defining forms normally appear at top level, it is
meaningful to place them in non-top-level contexts. Furthermore,
defmacro
should define the expander function within the
enclosing lexical environment, not within the global environment.
X3J13 voted in March 1988 (FLET-IMPLICIT-BLOCK) to specify that the
body of the expander function defined by defmacro
is
implicitly enclosed in a block
construct whose name is the
same as the name of the defined macro. Therefore
return-from
may be used to exit from the function.
The name is returned as the value of the
defmacro
form.
If we view the macro call as a list containing a function name and
some argument forms, in effect the expander function and the list of
(unevaluated) argument forms is given to apply
. The
parameter specifiers are processed as for any lambda-expression, using
the macro-call argument forms as the arguments. Then the body forms are
evaluated as an implicit progn
, and the value of the last
form is returned as the expansion of the macro call.
If the optional documentation string doc-string is present
(if not followed by a declaration, it may be present only if at least
one form is also specified, as it is otherwise taken to be a
form), then it is attached to the name as a
documentation string of type function
; see
documentation
.
Like the lambda-list in a defun
, a defmacro
lambda-list may contain the lambda-list keywords
&optional
, &rest
,
&key
, &allow-other-keys
, and
&aux
. For &optional
and
&key
parameters, initialization forms and supplied-p
parameters may be specified, just as for defun
. Three
additional markers are allowed in defmacro
variable lists
only.
These three markers are now allowed in other constructs as well.
&body
This is identical in function to &rest
, but it informs
certain output-formatting and editing functions that the remainder of
the form is treated as a body and should be indented accordingly. (Only
one of &body
or &rest
may be
used.)
&whole
This is followed by a single variable that is bound to the entire
macro-call form; this is the value that the macro definition function
receives as its single argument. &whole
and the
following variable should appear first in the lambda-list, before any
other parameter or lambda-list keyword.
&environment
This is followed by a single variable that is bound to an environment
representing the lexical environment in which the macro call is to be
interpreted. This environment may not be the complete lexical
environment; it should be used only with the function
macroexpand
for the sake of any local macro definitions
that the macrolet
construct may have established within
that lexical environment. This is useful primarily in the rare cases
where a macro definition must explicitly expand any macros in a subform
of the macro call before computing its own expansion.
See lambda-list-keywords
.
Notice of correction. In the first edition, the symbol
&environment
at the left margin above was inadvertently
omitted.
X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT) to specify
that macro environment objects received with the
&environment
argument of a macro function have only
dynamic extent. The consequences are undefined if such objects are
referred to outside the dynamic extent of that particular invocation of
the macro function. This allows implementations to use somewhat more
efficient techniques for representing environment objects.
X3J13 voted in March 1989 (DEFMACRO-LAMBDA-LIST) to clarify the
permitted uses of &body
, &whole
, and
&environment
:
&body
may appear at any level of a
defmacro
lambda-list.&whole
may appear at any level of a
defmacro
lambda-list. At inner levels a
&whole
variable is bound to that part of the argument
that matches the sub-lambda-list in which &whole
appears. No matter where &whole
is used, other
parameters or lambda-list keywords may follow it.&environment
may occur only at the outermost level
of a defmacro
lambda-list, and it may occur at most once,
but it may occur anywhere within that lambda-list, even before an
occurrence of &whole
.defmacro
, unlike any other Common Lisp construct that
has a lambda-list as part of its syntax, provides an additional facility
known as destructuring.
See destructuring-bind
, which provides the destructuring
facility separately.
Anywhere in the lambda-list where a parameter name may appear, and
where ordinary lambda-list syntax (as described in section 5.2.2) does not
otherwise allow a list, a lambda-list may appear in place of the
parameter name. When this is done, then the argument form that would
match the parameter is treated as a (possibly dotted) list, to be used
as an argument forms list for satisfying the parameters in the embedded
lambda-list. As an example, one could write the macro definition for
dolist
in this manner:
(defmacro dolist ((var listform &optional resultform)
&rest body)
...)
More examples of embedded lambda-lists in defmacro
are
shown below.
Another destructuring rule is that defmacro
allows any
lambda-list (whether top-level or embedded) to be dotted, ending in a
parameter name. This situation is treated exactly as if the parameter
name that ends the list had appeared preceded by &rest
.
For example, the definition skeleton for dolist
shown above
could instead have been written
(defmacro dolist ((var listform &optional resultform)
. body)
...)
If the compiler encounters a defmacro
, the new macro is
added to the compilation environment, and a compiled form of the
expansion function is also added to the output file so that the new
macro will be operative at run time. If this is not the desired effect,
the defmacro
form can be wrapped in an
eval-when
construct.
It is permissible to use defmacro
to redefine a macro
(for example, to install a corrected version of an incorrect
definition), or to redefine a function as a macro. It is an error to
attempt to redefine the name of a special form (see table 5-1) as a macro. See
macrolet
, which establishes macro definitions over a
restricted lexical scope.
See also define-compiler-macro
.
Suppose, for the sake of example, that it were desirable to implement
a conditional construct analogous to the Fortran arithmetic IF
statement. (This of course requires a certain stretching of the
imagination and suspension of disbelief.) The construct should accept
four forms: a test-value, a neg-form, a
zero-form, and a pos-form. One of the last three forms
is chosen to be executed according to whether the value of the
test-form is positive, negative, or zero. Using
defmacro
, a definition for such a construct might look like
this:
(defmacro arithmetic-if (test neg-form zero-form pos-form)
(let ((var (gensym)))
`(let ((,var ,test))
(cond ((< ,var 0) ,neg-form)
((= ,var 0) ,zero-form)
(t ,pos-form)))))
Note the use of the backquote facility in this definition (see
section 22.1.3). Also
note the use of gensym
to generate a new variable name.
This is necessary to avoid conflict with any variables that might be
referred to in neg-form, zero-form, or
pos-form.
If the form is executed by the interpreter, it will cause the
function definition of the symbol arithmetic-if
to be a
macro associated with which is a two-argument expansion function roughly
equivalent to
(lambda (calling-form environment)
(declare (ignore environment))
(let ((var (gensym)))
(list 'let
(list (list 'var (cadr calling-form)))
(list 'cond
(list (list '< var '0) (caddr calling-form))
(list (list '= var '0) (cadddr calling-form))
(list 't (fifth calling-form))))))
The lambda-expression is produced by the defmacro
declaration. The calls to list
are the (hypothetical)
result of the backquote (`
) macro character and its
associated commas. The precise macro expansion function may depend on
the implementation, for example providing some degree of explicit error
checking on the number of argument forms in the macro call.
Now, if eval
encounters
(arithmetic-if (- x 4.0)
(- x)
(error "Strange zero")
x)
this will be expanded into something like
(let ((g407 (- x 4.0)))
(cond ((< g407 0) (- x))
((= g407 0) (error "Strange zero"))
(t x)))
and eval
tries again on this new form. (It should be
clear now that the backquote facility is very useful in writing macros,
since the form to be returned is normally a complex list structure,
typically consisting of a mostly constant template with a few evaluated
forms here and there. The backquote template provides a ``picture’’ of
the resulting code, with places to be filled in indicated by preceding
commas.)
To expand on this example, stretching credibility to its limit, we
might allow the pos-form and zero-form to be omitted,
allowing their values to default to nil
, in much the same
way that the else form of a Common Lisp if
construct may be omitted:
(defmacro arithmetic-if (test neg-form
&optional zero-form pos-form)
(let ((var (gensym)))
`(let ((,var ,test))
(cond ((< ,var 0) ,neg-form)
((= ,var 0) ,zero-form)
(t ,pos-form)))))
Then one could write
(arithmetic-if (- x 4.0) (print x))
which would be expanded into something like
(let ((g408 (- x 4.0)))
(cond ((< g408 0) (print x))
((= g408 0) nil)
(t nil)))
The resulting code is correct but rather silly-looking. One might rewrite the macro definition to produce better code when pos-form and possibly zero-form are omitted, or one might simply rely on the Common Lisp implementation to provide a compiler smart enough to improve the code itself.
Destructuring is a very powerful facility that allows the
defmacro
lambda-list to express the structure of a
complicated macro-call syntax. If no lambda-list keywords appear, then
the defmacro
lambda-list is simply a list, nested to some
extent, containing parameter names at the leaves. The macro-call form
must have the same list structure. For example, consider this macro
definition:
(defmacro halibut ((mouth eye1 eye2)
((fin1 length1) (fin2 length2))
tail)
...)
Now consider this macro call:
(halibut (m (car eyes) (cdr eyes))
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
This would cause the expansion function to receive the following values for its parameters:
Parameter Value
---------------------------------
mouth m
eye1 (car eyes)
eye2 (cdr eyes)
fin1 f1
length1 (count-scales f1)
fin2 f2
length2 (count-scales f2)
tail my-favorite-tail
---------------------------------
The following macro call would be in error because there would be no
argument form to match the parameter length1
:
(halibut (m (car eyes) (cdr eyes))
((f1) (f2 (count-scales f2)))
my-favorite-tail)
The following macro call would be in error because a symbol appears in the call where the structure of the lambda-list requires a list.
(halibut my-favorite-head
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
The fact that the value of the variable my-favorite-head
might happen to be a list is irrelevant here. It is the macro call
itself whose structure must match that of the defmacro
lambda-list.
The use of lambda-list keywords adds even greater flexibility. For
example, suppose it is convenient within the expansion function for
halibut
to be able to refer to the list whose components
are called mouth
, eye1
, and eye2
as head
. One may write this:
(defmacro halibut ((&whole head mouth eye1 eye2)
((fin1 length1) (fin2 length2))
tail)
Now consider the same valid macro call as before:
(halibut (m (car eyes) (cdr eyes))
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
This would cause the expansion function to receive the same values
for its parameters and also a value for the parameter
head
:
Parameter Value
------------------------------------------
head (m (car eyes) (cdr eyes))
------------------------------------------
The stipulation that an embedded lambda-list is permitted only where ordinary lambda-list syntax would permit a parameter name but not a list is made to prevent ambiguity. For example, one may not write
(defmacro loser (x &optional (a b &rest c) &rest z)
...)
because ordinary lambda-list syntax does permit a list following
&optional
; the list (a b ``&rest`` c)
would be interpreted as describing an optional parameter named
a
whose default value is that of the form b
,
with a supplied-p parameter named &rest
(not legal),
and an extraneous symbol c
in the list (also not legal). An
almost correct way to express this is
(defmacro loser (x &optional ((a b &rest c)) &rest z)
...)
The extra set of parentheses removes the ambiguity. However, the
definition is now incorrect because a macro call such as
(loser (car pool))
would not provide any argument form for
the lambda-list (a b ``&rest`` c)
, and so the default
value against which to match the lambda-list would be nil
because no explicit default value was specified. This is in error
because nil
is an empty list; it does not have forms to
satisfy the parameters a
and b
. The fully
correct definition would be either
(defmacro loser (x &optional ((a b &rest c) '(nil nil)) &rest z)
...)
or
(defmacro loser (x &optional ((&optional a b &rest c)) &rest z)
...)
These differ slightly: the first requires that if the macro call
specifies a
explicitly then it must also specify
b
explicitly, whereas the second does not have this
requirement. For example,
(loser (car pool) ((+ x 1)))
would be a valid call for the second definition but not for the first.
Next: Macro Expansion
Up: Macros
Previous: Macros
AI.Repository@cs.cmu.edu