为什么这个Lisp的宏作为一个整体的工作,即使每件不工作?(Why does this Lisp m

2019-09-23 05:51发布

我在读/采取切实可行的Common Lisp工作。 我在关于Lisp的建立一个测试框架的章节。

我有功能“测试 - +”,如下实施,它的工作原理:

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

请记住,我说, 它的工作原理 ,这就是为什么接下来是令人百思不得其解....

下面是一些代码,“测试 - +”是指:

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

现在,我一直在用煤泥macroexpand这些,一步一步做的(使用Ctrl-C RET,它被映射到macroexpand-1)。

因此,“检查”的“测试 - +”展开这一号召:

(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 [条件类型未结合的可变的]

现在,如果我采取相同的代码,请更换一个变量名gensym如“X”,它工作得很好。

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

  1. 在“测试 - +”宏观调控,要求这一切,工作正常。

  2. 在“结合,结果”的宏扩展宏运行。

  3. 如果我从“相结合,结果”宏观扩张删除gensym,它工作。

我可以推测的唯一的事情是,你不能使用代码包含与gensyms的字面用法。 如果是的话,为什么不呢,以及如何围绕一个工作? 如果这是不是说明,究竟是什么?

谢谢。

Answer 1:

的代码,被印刷和读回后,不再是相同的代码。 特别地,在两个实例#:G2867在印刷表示将被读回作为两个分开的符号(虽然共享相同的名称),而它们应在原来的内部表示相同的。

尝试设置*PRINT-CIRCLE*T保留身份在宏扩展码的打印表示。



Answer 2:

GENSYM创建uninterned符号。 当宏正常运行时,这是没有问题的,因为相同的符号uninterned正在整个表达式取代。

但是,当你复制并粘贴到表达的REPL,这不会发生。 #:告诉读者返回一个uninterned符号。 其结果是,每次出现#:G2867是一个不同的符号,你会得到的未绑定变量警告。

如果你这样做(setq *print-circle* t)这样做会使用MACROEXPAND之前#n=#n#符号到相同的符号联系在一起。



文章来源: Why does this Lisp macro as a whole work, even though each piece doesn't work?