即使每个部分都不起作用,为什么这个Lisp宏作为一个整体还是可以起作用的呢? [英] Why does this Lisp macro as a whole work, even though each piece doesn't work?

查看:81
本文介绍了即使每个部分都不起作用,为什么这个Lisp宏作为一个整体还是可以起作用的呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过实用的Lisp阅读/工作.我在有关在Lisp中构建测试框架的章节中.

I'm reading/working through Practical Common Lisp. I'm on the chapter about building a test framework in Lisp.

我具有如下实现的"test- +"功能,并且可以正常工作:

I have the function "test-+" implemented as below, and it works:

(defun test-+ ()
  (check
    (= (+ 1 2) 3)
    (= (+ 5 6) 11)
    (= (+ -1 -6) -7)))

记住,我说,有效,这就是为什么接下来的事情如此令人困惑的原因.

Remember, I said, it works, which is why what follows is so baffling....

以下是"test- +"所指的一些代码:

Here is some code that "test-+" refers to:

(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).

Now, what I've been doing is using Slime to macro-expand these, step by step (using ctrl-c RET, which is mapped to macroexpand-1).

因此,"test- +"的"check"调用扩展为:

So, the "check" call of "test-+" expands to this:

(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):

And it is THAT code, directly above this sentence, which doesn't work. If I paste that into the REPL, I get the following error (I'm using Clozure Common Lisp):

未绑定变量:#:G2867 [UNBOUND-VARIABLE类型的条件]

Unbound variable: #:G2867 [Condition of type UNBOUND-VARIABLE]

现在,如果我使用相同的代码,则将gensym替换为变量名称(例如"x"),就可以了.

Now, if I take that same code, replace the gensym with a variable name such as "x", it works just fine.

那么,我们如何解释以下惊喜:

So, how can we explain the following surprises:

  1. 调用所有这些的"test- +"宏可以正常工作.

  1. The "test-+" macro, which calls all of this, works fine.

组合结果"宏的宏扩展无法运行.

The macro-expansion of the "combine-results" macro does not run.

如果我从"combine-results"的宏扩展中删除gensym,它将 起作用.

If I remove the gensym from the macro-expansion of "combine-results", it does work.

我唯一可以推测的是,您不能使用包含gensyms的字面用法的代码.如果是这样,为什么不呢?一个人如何解决呢?如果这不是解释,那是什么?

The only thing I can speculate is that you cannot use code the contains literal usages of gensyms. If so, why not, and how does one work around that? And if that is not the explanation, what is?

谢谢.

推荐答案

在打印并读回该代码后,该代码不再是相同的代码.特别是,在打印的表示形式中#:G2867的两个实例将作为两个分离的符号(尽管使用相同的名称)被读回,而在原始内部表示形式中它们应该是相同的.

The code, after being printed and read back, is no longer the same code. In particular, the two instances of #:G2867 in the printed representation would be read back as two separated symbols (albeit sharing the same name), while they should be the same in the original internal representation.

尝试将*PRINT-CIRCLE*设置为T,以在宏扩展代码的打印表示形式中保留标识.

Try setting *PRINT-CIRCLE* to T to preserve the identity in the printed representation of the macro-expanded code.

这篇关于即使每个部分都不起作用,为什么这个Lisp宏作为一个整体还是可以起作用的呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆