我有下一段代码:
(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"
。
(compile-file "source.lisp")
的结果:
; compiling (IN-PACKAGE :CL-USER)
; compiling (DEFMACRO TEST0 ...)
; compiling (DEFMACRO TEST1 ...)test0: Expander phase: FORMtest0: Expander phase: FORM
(load "source.lisp")
的结果:
; #<PACKAGE "COMMON-LISP-USER">
; TEST0
test0: Expander phase: FORM
; TEST1
我只是不明白接下来的事情:
为什么嵌套子窗体(test0 form)
在test1
宏的定义中进行扩展和处理?为什么不在宏调用中处理它?</ p>
Common Lisp标准在哪里指定这种行为? eval-when
?文件编译?表格评估?
最后,为什么"test0: Expander phase: FORM"
在编译期间compile-file
打印两次,而在评估期间load
只打印一次?
我认为答案很明显,但我找不到答案。
答案 0 :(得分:5)
宏是对 code 进行操作的函数。
由于在Lisp中, code 只是一个
list
,
macro 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
安排该宏可以在
以下代码(本身包括递归代码),因此必须立即进行定义。