3
votes

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.

1

1 Answers

1
votes

I think I see my error. The second line in the macro-expansion above should actually be:

`(LET (,`(,#:G939 ,FROM) ,`(,#:G940 ,TO))

which is equivalent to what SBCL shows.