自分で考えて書いてみた。本に載っている例とは少しだけロジックが異なるが、同様に動作する。
(defmacro once-only ((&rest names) &body body) (let ((gensyms (loop for n in names collect (gensym)))) `(let (,@(loop for n in names for g in gensyms collect `(,g ,n))) (let (,@(loop for n in names collect `(,n (gensym)))) `(let (,,@(loop for n in names for g in gensyms collect ``(,,n ,,g))) ,,@body)))))
ところでこの中の (,@(loop …)) となっている部分を、次のように ,(loop …) に置き換えると、
(defmacro once-only ((&rest names) &body body) (let ((gensyms (loop for n in names collect (gensym)))) `(let ,(loop for n in names for g in gensyms collect `(,g ,n)) (let ,(loop for n in names collect `(,n (gensym))) `(let ,,(loop for n in names for g in gensyms collect ``(,,n ,,g)) ,,@body)))))
なぜか動作しなくなる(do-primesのコンパイルでエラー)。理由がよく分からない。with-gensyms は後者の形で動いているのに…。