我正在尝试学习常见的Lisp语言,并且作为宏编写的练习,我正在尝试创建一个定义任意深度嵌套do循环的宏。我在使用emacs和slime, 以sbcl为基础进行编写。
首先,我编写了这个双重循环宏:
(defmacro nested-do-2 (ii jj start end &body body)
`(do ((,ii ,start (1+ ,ii)))
((> ,ii ,end))
(do ((,jj ,ii (1+ ,jj)))
((> ,jj ,end))
,@body)))
我可以将其用作以下方式:
(nested-do-2 ii jj 10 20 (print (+ ii jj)))
顺便说一下,我最初使用gensym生成循环计数器(ii,jj)编写了这个宏,但后来我意识到如果不能在主体中访问计数器,那么这个宏就没什么用了。
无论如何,我想将该宏概括为一个嵌套-do循环,可以嵌套到任意级别。这是我目前的成果,但它并不完全有效:
(defmacro nested-do ((&rest indices) start end &body body)
`(dolist ((index ,indices))
(do ((index ,start (1+ index)))
((> index ,end))
(if (eql index (elt ,indices (elt (reverse ,indices) 0)))
,@body))))
我希望您能按照以下方式调用它:
(nested-do (ii jj kk) 10 15 (print (+ ii jj kk)))
然而,列表未能正确扩展,我最终在调试器中遇到了这个错误:
error while parsing arguments to DEFMACRO DOLIST:
invalid number of elements in
((INDEX (II JJ KK)))
如果不明显,嵌套的 if 语句的目的是仅在最内层循环中执行主体。这对我来说并不是非常优雅,而且它没有真正测试过(因为我还不能扩展参数列表),但这并不是这个问题的重点。
如何在宏中正确地扩展列表?问题出在宏语法还是函数调用中列表的表达式上?任何其他评论也将不胜感激。
提前致谢。
(defmacro nested-do indices start end &body body)
,并且让(indices ='(ii jj kk)
)。 - ApproachingDarknessFish