为什么在我的环境中编译 Common Lisp 宏会产生与书中不同的结果?有可能达到同样的目的吗?

Why does the compilation of a Common Lisp macro in my environment produce a different result from the book? Is it possible to achieve the same?

我正在尝试通过 Common Lisp:对符号计算的简单介绍 来学习 Common Lisp。此外,我正在使用 SBCL、Emacs 和 Slime。

在第14章的最后一章中,作者介绍了宏。在关于编译它的一节中,他提到:

Since macro expansion can happen at any time, you should not write macros that produce side effects, such as assignments or i/o. But it’s fine for the macro to expand into an expression that produces side effects.

作为说明错误宏的一种方式,他提供了以下示例:

(defmacro bad-announce-macro ()
 (format t "~%Hi mom!"))


(defun say-hi ()
 (bad-announce-macro))

> (compile ’say-hi)
Hi, mom!
SAY-HI

> (say-hi)
NIL

当我尝试在我的环境中模仿相同的东西时,我有一个 不同的 输出:


CL-USER> (defmacro bad-announce-macro ()
            (format t "~%Hi mom!"))
BAD-ANNOUNCE-MACRO
CL-USER> (bad-announce-macro)
Hi mom!
NIL
CL-USER> (defun say-hi ()
           (bad-announce-macro))
Hi mom!
SAY-HI
CL-USER> (say-hi)
NIL
CL-USER> (compile (say-hi))
; Evaluation aborted on #<UNDEFINED-FUNCTION NIL {100408C143}>.
CL-USER> (compile 'say-hi)
SAY-HI
NIL
NIL
CL-USER> (compile `say-hi)
SAY-HI
NIL
NIL

如您所见,在编译函数时,缺少 Hi mom! 部分。

为什么会这样?这仅仅是因为 Lisp 实现的差异吗? 是否可以实现相同的输出?

我认为情况并非如此,但我会放一个书中的打印屏幕,以防这与从 pdf 复制并粘贴到 Emacs Slime 的 REPL 中有关。

SBCL 默认已经编译了 REPL 中的定义。在已编译的函数上调用 compile 然后可能什么都不做。

执行 defun 表单时,已经打印了 Hi, mom! 消息。请参阅上面的示例。

Touretzky 在他的书中使用了不同的实现,它在 REPL 中使用了解释器。然后,编译器将由用户通过调用 compilecompile-file 或类似的方式调用。