私は Practical Common Lisp を読んだり作業したりしています。私は、Lisp でのテスト フレームワークの構築に関する章にいます。
以下のように機能「test-+」を実装しましたが、動作します:
(defun test-+ ()
(check
(= (+ 1 2) 3)
(= (+ 5 6) 11)
(= (+ -1 -6) -7)))
覚えておいてください、私は言った、それは機能します.
「test-+」が参照するコードは次のとおりです。
(defmacro check (&body forms)
`(combine-results
,@(loop for f in forms collect `(report-result ,f ',f))))
(defmacro combine-results (&body forms)
(with-gensyms (result)
`(let ((,result t))
,@(loop for f in forms collect `(unless ,f (setf ,result nil)))
,result)))
(defmacro with-gensyms ((&rest names) &body body)
`(let ,(loop for n in names collect `(,n (gensym)))
,@body))
(defun report-result (value form)
(format t "~:[FAIL~;pass~] ... ~a~%" value form)
value)
今、私が行っていることは、Slime を使用して、これらを段階的にマクロ展開することです (マクロ展開 1 にマップされている ctrl-c RET を使用)。
したがって、「test-+」の「check」呼び出しは次のように展開されます。
(COMBINE-RESULTS
(REPORT-RESULT (= (+ 1 2) 3) '(= (+ 1 2) 3))
(REPORT-RESULT (= (+ 5 6) 11) '(= (+ 5 6) 11))
(REPORT-RESULT (= (+ -1 -6) -7) '(= (+ -1 -6) -7)))
そして、これをマクロ展開すると、次のようになります。
(LET ((#:G2867 T))
(UNLESS (REPORT-RESULT (= (+ 1 2) 3) '(= (+ 1 2) 3)) (SETF #:G2867 NIL))
(UNLESS (REPORT-RESULT (= (+ 5 6) 11) '(= (+ 5 6) 11)) (SETF #:G2867 NIL))
(UNLESS (REPORT-RESULT (= (+ -1 -6) -7) '(= (+ -1 -6) -7))
(SETF #:G2867 NIL))
#:G2867)
そして、この文の真上にあるそのコードが機能しません。これを REPL に貼り付けると、次のエラーが表示されます (Clozure Common Lisp を使用しています)。
アンバウンド変数: #:G2867 [タイプ UNBOUND-VARIABLE の条件]
同じコードを使用して、gensym を "x" などの変数名に置き換えると、問題なく動作します。
では、次の驚きをどのように説明できますか。
これらすべてを呼び出す「test-+」マクロは正常に動作します。
「combine-results」マクロのマクロ展開は実行されません。
「combine-results」のマクロ展開からgensymを削除すると、機能 します。
私が推測できる唯一のことは、gensyms の文字通りの使用を含むコードを使用できないということです。もしそうなら、それはなぜですか、そしてそれをどのように回避しますか? そして、それが説明でないなら、それは何ですか?
ありがとう。