Common Lisp the Language, 2nd Edition


next up previous contents index
Next: Macro Expansion Up: Macros Previous: Macros

8.1. Macro Definition

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.

old_change_begin

[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.
old_change_end

change_begin
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.
change_end


[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.

old_change_begin
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.
old_change_end

change_begin
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.
change_end

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.

old_change_begin
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.
old_change_end

change_begin
These three markers are now allowed in other constructs as well.
change_end

&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.

change_begin
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:

change_end

defmacro, unlike any other Common Lisp construct that has a lambda-list as part of its syntax, provides an additional facility known as destructuring.

change_begin
See destructuring-bind, which provides the destructuring facility separately.
change_end

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.

change_begin
See also define-compiler-macro.
change_end

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 up previous contents index
Next: Macro Expansion Up: Macros Previous: Macros


AI.Repository@cs.cmu.edu