编辑:在我的例子中,=>
意思是“评估到”,->
意思是“扩展到下面macroexpand-1
”。
我正试图围绕 Common Lisp 中的嵌套反引号,我想我非常接近理解它,这要归功于其他几个 SO 问题(请不要向我介绍他们——我已经看过他们)。只有最后一件事困扰着我。考虑:
`(a `(b ,,@(list 'c 'd)))
=> (a `(b ,c ,d))
遵循 CLHS 中扩展反引号形式的算法,我逐步完成了上述第一种形式的(读取时)扩展过程,实际上,评估从该扩展获得的形式确实给出了等效的结果。现在,考虑一下once-only
Peter Seibel 在他的优秀著作中给出的定义。
(defmacro once-only ((&rest names) &body body)
(let ((gensyms (loop for n in names collect (gensym))))
`(let (,@(loop for g in gensyms collect `(,g (gensym))))
`(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
,@body)))))
鉴于该定义,SBCL 显示以下宏扩展:
(once-only (from to)
`(do ((,var ,from (next-prime (+ 1 ,var))))
((>= ,var ,to))
,@body)))
-> (LET ((#:G939 (GENSYM)) (#:G940 (GENSYM)))
`(LET ((,#:G939 ,FROM) (,#:G940 ,TO))
,(LET ((FROM #:G939) (TO #:G940))
`(DO ((,VAR ,FROM (NEXT-PRIME (+ ,1 ,VAR)))) ((>= ,VAR ,TO)) ,@BODY))))
现在,我的问题是扩展表单的第二行。不应该是:
`(LET (,(,#:G939 ,FROM) ,(,#:G940 ,TO))
?
看看,,@
上面第一个示例中的评估如何最终将逗号“分配”到从列表中拼接的元素(c d)
?为什么这里不会发生?这两个示例似乎具有相同的结构,但它们的评估结果似乎不一致。