Cha*_*ers 6 lisp macros common-lisp gensym
我正在通过Practical Common Lisp阅读/工作.我在关于在Lisp中构建测试框架的章节.
我的功能"test- +"实现如下,它的工作原理如下:
(defun test-+ ()
(check
(= (+ 1 2) 3)
(= (+ 5 6) 11)
(= (+ -1 -6) -7)))
Run Code Online (Sandbox Code Playgroud)
记住,我说,它有效,这就是为什么接下来是如此令人费解......
以下是"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)
Run Code Online (Sandbox Code Playgroud)
现在,我一直在做的是使用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)))
Run Code Online (Sandbox Code Playgroud)
然后是宏观膨胀成这样:
(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)
Run Code Online (Sandbox Code Playgroud)
并且直接在这句话之上的那个代码不起作用.如果我将其粘贴到REPL中,我会收到以下错误(我正在使用Clozure Common Lisp):
未绑定变量:#:G2867 [UNBOUND-VARIABLE类型的条件]
现在,如果我使用相同的代码,用变量名称替换gensym,例如"x",它就可以了.
那么,我们如何解释以下惊喜:
调用所有这些的"test- +"宏工作正常.
"组合结果"宏的宏扩展不会运行.
如果我从"结果 - 结果"的宏扩展中删除gensym,它 确实有效.
我唯一可以推测的是你不能使用代码包含gensyms的文字用法.如果是这样,为什么不,以及如何解决这个问题呢?如果那不是解释,那是什么?
谢谢.
hua*_*uan 11
打印和回读后的代码不再是相同的代码.特别是,#:G2867打印表示中的两个实例将作为两个分开的符号(虽然共享相同的名称)读回,而它们在原始内部表示中应该相同.
尝试设置*PRINT-CIRCLE*为T在宏扩展代码的打印表示中保留标识.
Bar*_*mar 11
GENSYM创建不带符号的符号.当宏正常运行时,这不是问题,因为在整个表达式中替换了相同的未处理符号.
但是当您将表达式复制并粘贴到REPL中时,这不会发生.#:告诉读者返回一个未加工的符号.因此,每次出现的#:G2867都是不同的符号,您将获得未绑定的变量警告.
如果你(setq *print-circle* t)在做MACROEXPAND之前你会使用#n=和#n#表示法将相同的符号链接在一起.
| 归档时间: |
|
| 查看次数: |
469 次 |
| 最近记录: |