5
votes

In his book ANSI Common Lisp, p.320, Paul Graham writes of macrolet: "Like flet, the local macros may not call one another."

Maybe I misunderstand this but I can't think of any way in which it could be true. Macros do not call each other so much as expand into each other and the nature of macro expansion is such that it continues until all macros defined in the scope have been expanded away.

Code such as the following disagrees with Graham in every implentation of Common Lisp I've tried:

(macrolet ((jump (x) `(car ,x))
           (skip (x) `(jump ,x))
           (hop (x) `(skip ,x)))
  (hop '(1 2 3))) 

=> 1

(macrolet ((yin (n x)
             (if (zerop n)
                 `(cdr ,x)
                 `(yang ,(1- n) ,x)))
           (yang (n x)
             (if (zerop n)
                 `(car ,x)
                 `(yin ,(1- n) ,x))))
      (yin 6 '(1 2 3)))

=> (2 3)

Is Graham's statement in error?

1
This statement is questionable given the ANSI spec, as it doesn't specify anything about macrolet definitions being mutually recursive or not. However, given what is described in CTLT2, you can understand the historic context. - acelent

1 Answers

8
votes

It is okay for a macro defined by macrolet to expand into the use of a different macro defined in the same macrolet. It is incorrect for a macro defined by macrolet to directly use a different macro defined in the same macrolet. For example:

(macrolet ((jump (x) `(car ,x))
           ;; Okay since skip expands into jump.
           (skip (x) `(jump ,x)))
  (skip '(1 2 3))) 

=> 1

as opposed to

(macrolet ((jump (x) `(car ,x))
           ;; Wrong since skip uses jump directly.
           (skip (x) (jump x)))
  (skip '(1 2 3))) 

=> Error: The function COMMON-LISP-USER::JUMP is undefined.