在代码编译/评估期间扩展嵌套宏调用

时间:2018-11-16 13:13:17

标签: common-lisp

我有下一段代码:

(in-package :cl-user)

(defmacro test0 (form)
  (format t "test0: Expander phase: ~s" form)
  `(format t "test0: Expansion phase: ~s" ,form))

(defmacro test1 (form)
  (format t "test1: Expander phase: ~s" form)
  (test0 form)
  `(format t "test1: Expansion phase: ~s" ,form))

Lisp的常见实现:"SBCL 1.3.16"

  1. (compile-file "source.lisp")的结果: ; compiling (IN-PACKAGE :CL-USER) ; compiling (DEFMACRO TEST0 ...) ; compiling (DEFMACRO TEST1 ...)test0: Expander phase: FORMtest0: Expander phase: FORM

  2. (load "source.lisp")的结果: ; #<PACKAGE "COMMON-LISP-USER"> ; TEST0 test0: Expander phase: FORM ; TEST1

我只是不明白接下来的事情:

  1. 为什么嵌套子窗体(test0 form)test1宏的定义中进行扩展和处理?为什么不在宏调用中处理它?<​​/ p>

  2. Common Lisp标准在哪里指定这种行为? eval-when?文件编译?表格评估?

  3. 最后,为什么"test0: Expander phase: FORM"在编译期间compile-file打印两次,而在评估期间load只打印一次?

我认为答案很明显,但我找不到答案。

1 个答案:

答案 0 :(得分:5)

是对 code 进行操作的函数。 由于在Lisp中, code 只是一个 listmacro functions看起来像普通功能。

您的defmacro test1被视为函数的定义,因此当SBCL编译(test0 form)时,所有代码都会得到适当处理,并且defmacro test1被宏扩展。这回答了q1。

load“按顺序执行 遇到的每种形式”,因此要回答您的q2,您需要阅读3.1 Evaluation,特别是, 3.1.2.1.2.2 Macro Forms

关于宏扩展了多少次,这没有由宏指定 标准(一个实现可以在用户的​​每次调用时对其进行扩展 函数!),这就是为什么它不是宏的好主意的原因 产生副作用(例如进行输出)。 在您的情况下,定义test1时需要扩展加载。 编译在定义test1时扩展,然后在定义时再次扩展 编译它。 请记住,defmacro安排该宏可以在 以下代码(本身包括递归代码),因此必须立即进行定义。