所以我有这个宏(基本上是for循环):
(defmacro for ((parameter start-value end-value &optional (step 1)) &body e)
(let ((func-name (gensym))
(end (gensym)))
`(labels ((,func-name (,parameter ,end)
(if (<= ,parameter ,end)
(progn ,@e
(,func-name (+ ,parameter ,step) ,end)))))
(,func-name ,start-value ,end-value))))
我想用它来测试它:
(print (let ((j 0) (k 1))
(for (i 1 10 (incf k)) (print i))))
我现在得到的是:
1, 3, 6, 10, NIL.
这意味着我的步骤在每次迭代后递增,但我希望它在此输出的开头只增加一次:
1, 3, 5, 7, 9, NIL.
我的宏有什么问题,我该怎么办?
答案 0 :(得分:2)
您需要计算循环外的步长值:
CL-USER 12 > (defmacro for ((parameter start-value end-value
&optional (step 1))
&body e)
(let ((func-name (gensym))
(step-name (gensym))
(end (gensym)))
`(labels ((,func-name (,parameter ,end ,step-name)
(when (<= ,parameter ,end)
,@e
(,func-name (+ ,parameter ,step-name)
,end
,step-name))))
(,func-name ,start-value ,end-value ,step))))
FOR
CL-USER 13 > (pprint (macroexpand-1 '(for (i 1 10 (incf k)) (print i))))
(LABELS ((#:G954 (I #:G956 #:G955)
(WHEN (<= I #:G956) (PRINT I) (#:G954 (+ I #:G955) #:G956 #:G955))))
(#:G954 1 10 (INCF K)))
CL-USER 14 > (let ((j 0) (k 1))
(for (i 1 10 (incf k))
(print i)))
1
3
5
7
9
NIL
如果您不想一直传递步长值,则需要外部LET
绑定其值。
注意:一些Lisp实现(许多解释器和一些编译器)不支持TCO(尾部调用优化)。