我有下一段代码:
(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宏的定义中被扩展和处理?为什么它不在宏调用中处理呢?eval-when?文件编译?表格评估?"test0: Expander phase: FORM"在编译期间(compile-file)只打印两次,在计算期间(load)只打印一次?我认为答案很明显,但我找不到。
发布于 2018-11-16 14:31:12
宏是对代码进行操作的函数。因为在Lisp中,代码只是一个list,所以宏函数看起来像普通的函数。
您的defmacro test1被看作是函数的定义,所以当SBCL编译defmacro test1时,所有的代码都会被适当地处理,并且(test0 form)会被宏扩展。这回答了q1。
load“依次执行它遇到的每个表单”,因此要回答您的q2,您需要读取3.1评价,特别是3.1.2.1.2.2宏观形式。
至于一个宏展开了多少次,这不是由标准指定的(实现可以在用户函数的每个调用中扩展它!),这也是为什么宏产生副作用(例如,进行输出)不是一个好主意的原因。在您的情况下,当定义test1时,加载需要扩展。编译在定义test1时扩展,然后在编译时再次扩展。记住,defmacro安排宏可以在下面的代码中使用(包括递归地使用),因此必须立即定义。
https://stackoverflow.com/questions/53338637
复制相似问题