ccQ*_*ein 2 lisp macros compilation sbcl common-lisp
我在一个文件中写了一个宏和一个函数,如下所示:
(defun test ()
(let ((x '(1 2 3)))
(macro-test (x real-b)
(print (+ 1 (car real-b))))))
(defmacro macro-test ((a b) &body body)
`(do ((,b ,a (cdr ,b)))
((not ,b))
,@body))
Run Code Online (Sandbox Code Playgroud)
然后我在 repl 中加载这个文件并运行(test). 我收到此错误:
The variable REAL-B is unbound.
Run Code Online (Sandbox Code Playgroud)
然而,当我defmacro 之前 把defun. 一切安好。
我对常见的 lisp 编译顺序感到困惑。我知道如果defmacro在里面使用一些函数,那些函数应该(eval-when (:compile-toplevel :load-toplevel :execute)),否则编译会失败。
但是,如果编译时宏定义和函数定义相同,那么顺序就是问题,对吗?宏应位于使用它们之前的位置(如果我创建两个函数,则顺序无关紧要)。我可以得到更多关于 SBCL 编译顺序的细节吗?它仅适用于 SBCL 吗?还是按照 Common Lisp 的标准?
谢谢!
顺序总是很重要:当你想使用宏时,它必须是已知的。宏执行源转换。您将如何使用未知宏进行源转换?
Common Lisp 标准不需要多遍编译,即首先读取所有源代码并收集所有宏,然后从文件顶部开始编译。Common Lisp 中的文件编译只是从头到尾遍历源代码。稍后可能会有多个编译阶段,但这留给实现......
test当宏macro-test未知时,Lisp 应该如何编译函数?Lisp 编译器需要 a) 知道它是一个宏 b) 它需要有它的定义来扩展宏形式。
对于 Common Lisp,这是一个基本规则:
如果我们有一个表格,(foo bar baz)那么评估基本上是看foo。
foo是特殊运算符 -> 使用该特殊运算符foo是宏运算符 -> 宏展开代码并重新开始foo是一个函数 -> 使用评估参数调用该函数在编译时它看起来很相似:
foo是一个特殊的运算符 -> 编译那个特殊的形式foo是宏运算符 -> 宏展开宏形式并编译该代码foo是一个函数 -> 编译该函数形式foo是一个函数并编译对该名称的未来函数的调用