Edit: In my examples, =>
means "evaluates to", and ->
means "expands to under macroexpand-1
".
I'm trying to wrap my head around nested back-quoting in Common Lisp, and I think I'm very close to understanding it, thanks to several other SO questions (please don't refer me to them--I've seen them). There's just one last thing that's nagging me. Consider:
`(a `(b ,,@(list 'c 'd)))
=> (a `(b ,c ,d))
Following the algorithm for expanding back-quoted forms in CLHS, I stepped through the (read-time) expansion process of the first form above, and indeed, evaluating the form obtained from that expansion does give an equivalent result. Now, consider the definition of once-only
given by Peter Seibel in his excellent book.
(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)))))
Given that definition, SBCL shows the following macro expansion:
(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))))
Now, my issue is with the second line of the expanded form. Shouldn't it be:
`(LET (,(,#:G939 ,FROM) ,(,#:G940 ,TO))
?
See how the evaluation of the ,,@
in the first example above ends up "distributing" the comma to the elements spliced from the list (c d)
? Why doesn't that occur here? The two examples seem to share the same structure, but their evaluated results seem inconsistent.