Macro defmacro

Syntax:

defmacro name lambda-list ⟦{declaration}* | documentation⟧ {form}* name

Arguments and Values:

name—a symbol. !!! maybe call it a "user symbol" ?? -kmp 2-Aug-91 8.1.0 9 8.1.0 10 8.1.0 11 8.1.0 12lambda-list—a macro lambda list.

declaration—a declare expression; not evaluated.

documentation—a string; not evaluated.

form—a form.

Description:

8.1.0 6Defines name as a macro by associating a macro function with that name in the global environment. Reworded garbled text. --sjl 7 Mar 92 When the \term{macro function} is called, the \param{forms} are evaluated in the \term{lexical environment} in which the \macref{defmacro} form was evaluated.The macro function is defined in the same lexical environment in which the defmacro form appears.

8.1.0 7The parameter variables in lambda-list are bound to destructured portions of the macro call.

The expansion function accepts two arguments, a form and an environment. The expansion function returns a form. The body of the expansion function is specified by forms. Forms are executed in order. The value of the last form executed is returned as the expansion of the macro. The body forms of the expansion function (but not the lambda-list) are implicitly enclosed in a block whose name is name.

The lambda-list conforms to the requirements described in Section 3.4.4 (Macro Lambda Lists).

Documentation is attached as a documentation string to name (as kind function) and to the macro function.

8.1.0 17defmacro can be used to redefine a macro or to replace a function definition with a macro definition.

sandra says this is redundant The consequences are undefined if a \term{special form} is redefined using \macref{defmacro}.

Recursive expansion of the form returned must terminate, including the expansion of other macros which are subforms of other forms returned.

Per Moon#13 (first public review) -kmp 5-May-93The consequences are undefined if the result of fully macroexpanding a form contains any non-constant circular list structure.a form contains any circular list structure except in literal objects.

added qualification about top-level-ness --sjl 5 Mar 92If a defmacro form appears as a top level form, the compiler must store the macro definition at compile time, so that occurrences of the macro later on in the file can be expanded correctly. Users must ensure that the body of the macro can be evaluated at compile time if it is referenced within the file being compiled.

Examples:

 (defmacro mac1 (a b) "Mac1 multiplies and adds" 
            `(+ ,a (* ,b 3))) → MAC1 
 (mac1 4 5) → 19 
 (documentation 'mac1 'function) → "Mac1 multiplies and adds" 
 (defmacro mac2 (&optional (a 2 b) (c 3 d) &rest x) `'(,a ,b ,c ,d ,x)) → MAC2 
 (mac2 6) → (6 T 3 NIL NIL) 
 (mac2 6 3 8) → (6 T 3 T (8)) 
 (defmacro mac3 (&whole r a &optional (b 3) &rest x &key c (d a))
    `'(,r ,a ,b ,c ,d ,x)) → MAC3 
 (mac3 1 6 :d 8 :c 9 :d 10) → ((MAC3 1 6 :D 8 :C 9 :D 10) 1 6 9 8 (:D 8 :C 9 :D 10)) 
(defmacro mac4 (&whole (su &rest (p &rest q)) a optional (b 3) &rest x &key c (d a)) `'(,su ,p ,a ,b ,c ,d ,x)) \EV MAC4 (mac4 1 6 :d 8 :c 9 :d 10) \EV (MAC4 1 1 6 9 8 (:D 8 :C 9 :D 10))

An example of destructuring follows: \code (defmacro halibut ((mouth eye1 eye2) ((fin1 length1) (fin2 length2)) tail) ...) \endcode Now consider this macro call: \code (halibut (m (car eyes) (cdr eyes)) ((f1 (count-scales f1)) (f2 (count-scales f2))) my-favorite-tail) \EV NIL \endcode This would cause the expansion function to receive the values in \thenextfigure\ for its parameters: \boxfig \tabskip \dimen0 plus .5 fil \halign to \hsize {#\hfil\tabskip \dimen0 plus 1fil&#\hfil \noalign{\vskip -9pt} \hfil{{\sl Parameter\/}} & {{\sl Value\/}} \noalign{\vskip 2pt\hrule\vskip 2pt} mouth & m eye1 & (car eyes) eye2 & (cdr eyes) fin1 & f1 length1 & (count-scales f1) fin2 & f2 length2 & (count-scales f2) tail & my-favorite-tail \noalign{\vskip -9pt} }} \caption{Destructuring example expansion function values} \endfig The following macro call would be in error because there would be no argument form to match the parameter \f{length1}: \code (halibut (m (car eyes) (cdr eyes)) ((f1) (f2 (count-scales f2))) my-favorite-tail) \endcode The following macro call would be in error because a \term{symbol} appears in the call where the structure of the \term{lambda list} requires a \term{list}: \code (halibut my-favorite-head ((f1 (count-scales f1)) (f2 (count-scales f2))) my-favorite-tail) \endcode The fact that the value of the variable \f{my-favorite-head} might happen to be a \term{list} is irrelevant here. It is the macro call itself whose structure must match that of the \macref{defmacro} \term{lambda list}. 8.1.0 25 The use of \term{lambda list keywords} is illustrated as follows. Suppose it is convenient within the expansion function for \f{halibut} to be able to refer to the \term{list} whose components are called \f{mouth}, \f{eye1}, and \f{eye2} as \f{head}. This may be written as follows: \code (defmacro halibut ((&whole head mouth eye1 eye2) ((fin1 length1) (fin2 length2)) tail) ...) \endcode Now consider the same valid macro call as before: \code (halibut (m (car eyes) (cdr eyes)) ((f1 (count-scales f1)) (f2 (count-scales f2))) my-favorite-tail) \EV NIL \endcode This would cause the expansion function to receive the same values for its parameters and also a value for the parameter \f{head} as in \thenextfigure. \boxfig \tabskip \dimen0 plus .5 fil \halign to \hsize {#\hfil\tabskip \dimen0 plus 1fil&#\hfil \noalign{\vskip -9pt} \hfil{{\sl Parameter\/}} & {{\sl Value\/}} \noalign{\vskip 2pt\hrule\vskip 2pt} head & (m (car eyes) (cdr eyes)) \noalign{\vskip -9pt} }} \caption{Lambda list keywords expansion function values example} \endfig 8.1.0 19 The following implements a conditional \term{form} analogous to the \fortran\ arithmetic IF statement. The \term{form} should accept four argument forms: a \f{test-value}, a \f{neg-form}, a \f{zero-form}, and a \f{pos-form}. One of the last three forms is chosen to be executed according to whether the value of the \f{test-form} is positive, negative, or zero. Using \macref{defmacro}, a definition for such a \term{form} might look like this: \code (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))))) \EV ARITHMETIC-IF \endcode Note the use of the backquote facility in this definition, and also the use of \funref{gensym} to generate a new variable name. This is necessary to avoid conflict with any variables that might be referred to in \f{neg-form}, \f{zero-form}, or \f{pos-form}. 8.1.0 20 If the form is executed by the interpreter, it will cause the function definition of the symbol \f{arithmetic-if} to be a macro associated with which is a two-argument expansion function roughly equivalent to: \code (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)))))) \endcode

Barmar had noted that if we were going to show the above lambda, we should show the defmacro that might have produced it. But since we're not going to show it, I guess the issue is moot. -kmp 28-Dec-90 8.1.0 21 The \term{lambda expression} could have been produced by the \macref{defmacro} macro. The calls to \funref{list} are the (hypothetical) result of the backquote (\f{\bq}) macro character and its associated commas. The precise macro expansion function might depend on the implementation. For example, the implementation might provide some degree of explicit error checking on the number of argument forms in the macro call. 8.1.0 22 If \funref{eval} encounters \code (arithmetic-if (- x 4.0) (- x) (error "Strange zero") x) \endcode this will be expanded into something like \code (let ((g407 (- x 4.0))) (cond ((< g407 0) (- x)) ((= g407 0) (error "Strange zero")) (t x))) \endcode and \funref{eval} tries again on this new form. 8.1.0 23 To expand on this example the \f{pos-form} and \f{zero-form} could be omitted, allowing their values to default to \nil, in the same way that the \f{else} form of \specref{if} may be omitted: \code (defmacro arithmetic-if (test neg-form &optional zero-form pos-form) (let ((var (gensym))) \bq(let ((,var ,test)) (cond ((< ,var 0) ,neg-form) ((= ,var 0) ,zero-form) (t ,pos-form))))) \endcode Then \code (arithmetic-if (- x 4.0) (print x)) \endcode would be expanded into something like \code (let ((g408 (- x 4.0))) (cond ((< g408 0) (print x)) ((= g408 0) nil) (t nil))) \endcode

8.1.0 26The stipulation that an embedded destructuring 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, the following is not valid:

 (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 valid), and an extraneous symbol c in the list (also not valid). 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. The consequences of this are unspecified since the empty list, nil, 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.

 (defmacro dm1a (&whole x) `',x)
 (macroexpand '(dm1a))  → (QUOTE (DM1A))
 (macroexpand '(dm1a a)) is an error.
 
 (defmacro dm1b (&whole x a &optional b) `'(,x ,a ,b))
 (macroexpand '(dm1b))  is an error.
 (macroexpand '(dm1b q))  → (QUOTE ((DM1B Q) Q NIL))
 (macroexpand '(dm1b q r)) → (QUOTE ((DM1B Q R) Q R))
 (macroexpand '(dm1b q r s)) is an error.

 (defmacro dm2a (&whole form a b) `'(form ,form a ,a b ,b))
 (macroexpand '(dm2a x y)) → (QUOTE (FORM (DM2A X Y) A X B Y))
 (dm2a x y) → (FORM (DM2A X Y) A X B Y)

 (defmacro dm2b (&whole form a (&whole b (c . d) &optional (e 5)) 
                 &body f &environment env)
   ``(,',form ,,a ,',b ,',(macroexpand c env) ,',d ,',e ,',f))
 ;Note that because backquote is involved, implementations may differ
 ;slightly in the nature (though not the functionality) of the expansion.
 (macroexpand '(dm2b x1 (((incf x2) x3 x4)) x5 x6))
 → (LIST* '(DM2B X1 (((INCF X2) X3 X4))
                   X5 X6)
            X1
            '((((INCF X2) X3 X4)) (SETQ X2 (+ X2 1)) (X3 X4) 5 (X5 X6))),
     T
 (let ((x1 5))
   (macrolet ((segundo (x) `(cadr ,x)))
     (dm2b x1 (((segundo x2) x3 x4)) x5 x6)))
 → ((DM2B X1 (((SEGUNDO X2) X3 X4)) X5 X6)
      5 (((SEGUNDO X2) X3 X4)) (CADR X2) (X3 X4) 5 (X5 X6))

Affected By:

None.

Exceptional Situations:

None.

See Also:

define-compiler-macro, destructuring-bind, documentation, macroexpand, *macroexpand-hook*, macrolet, macro-function, Section 3.1 (Evaluation), Section 3.2 (Compilation), Section 3.4.11 (Syntactic Interaction of Documentation Strings and Declarations)

Notes:

None.