我正在阅读/使用 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 一步一步地对它们进行宏扩展(使用 ctrl-c RET,它映射到 macroexpand-1)。
因此,“test-+”的“检查”调用扩展为:
(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”宏的宏扩展不运行。
如果我从“组合结果”的宏扩展中删除 gensym,它 确实有效。
我唯一可以推测的是,您不能使用包含 gensyms 文字用法的代码。如果是这样,为什么不呢?如何解决这个问题?如果这不是解释,那是什么?
谢谢。