Common Lisp the Language, 2nd Edition

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.

[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