This recursive definition of a macro does what it should (sum integers from 1 to n):
(defmacro sum-int-seq (n)
`(cond
((equal 0 ,n) 0)
(t (+ ,n (sum-int-seq (- ,n 1))))))
For example (sum-int-seq 5) gives 15.
But why does it work? When the macro gets expanded i get this:
(macroexpand '(sum-int-seq 5))
(IF (EQUAL 0 5) 0 (+ 5 (SUM-INT-SEQ (- 5 1))))
But because sum-int-seq is a macro the macro evaluation should become an infinite loop. Does the compiler create a recursive function instead? If this definition creates a recursive function is there any way to define macros recursively?
(This is a silly example for the sake of brevity, a function would of course work better for this)
Your example does not work.
It may work in an interpreter. But with a compiler you’ll see an endless loop during compilation.
Let’s use the LispWorks interpreter:
Let’s try to compile the function:
So, now the next question: why does it work in the interpreter, but the compiler can’t compile it?
Okay, I’ll explain it.
Let’s look at the interpreter first.
(sum-int-seq 5).(COND ((EQUAL 0 5) 0) (T (+ 5 (SUM-INT-SEQ (- 5 1))))).(+ 5 (SUM-INT-SEQ (- 5 1))). For that it needs to macroexpand(SUM-INT-SEQ (- 5 1)).(cond ((EQUAL 0 (- (- (- (- (- 5 1) 1) 1) 1) 1)) 0) .... Which then will return 0 and the computation can use this result and add the other terms to it.The interpreter takes the code, evaluates what it can and macroexpands if necessary. The generated code is then evaluated or macroexpanded. And so on.
Now let’s look at the compiler.
(COND ((EQUAL 0 5) 0) (T (+ 5 (SUM-INT-SEQ (- 5 1))))).(SUM-INT-SEQ (- 5 1)). note that the code never gets evaluated, only expanded.(SUM-INT-SEQ (- (- 5 1) 1))and so forth. finally you’ll see a stack overflow.The compiler walks (recursively compiles / expands) the code. It may not execute the code (unless it does optimizations or a macro actually evaluates it explicitly).
For a recursive macro you’ll need to actually count down. If you eval inside the macro, then something like
(sum-int-seq 5)can made work. But for(defun foo (n) (sum-int-seq n))this is hopeless, since the compiler does not know what the value of n is.