Compilation 关于公共Lisp编译顺序的问题

Compilation 关于公共Lisp编译顺序的问题,compilation,macros,lisp,common-lisp,sbcl,Compilation,Macros,Lisp,Common Lisp,Sbcl,我在一个文件中编写了宏和函数,如下所示: (defun测试() (让((x'(1 2 3))) (宏观测试(x real-b) (打印(+1(car real-b()()))) (DEF宏观测试((a b)和车身) `(do(,b,a(cdr,b))) ((不,b)) (@body)) 然后我在repl中加载这个文件并运行(test)。我得到了这个错误: The variable REAL-B is unbound. 但是,当我将defmacro放在defun之前时。一切都很好 我对公共li

我在一个文件中编写了宏和函数,如下所示:

(defun测试()
(让((x'(1 2 3)))
(宏观测试(x real-b)
(打印(+1(car real-b()())))
(DEF宏观测试((a b)和车身)
`(do(,b,a(cdr,b)))
((不,b))
(@body))
然后我在repl中加载这个文件并运行
(test)
。我得到了这个错误:

The variable REAL-B is unbound.
但是,当我将
defmacro
放在
defun
之前时。一切都很好

我对公共lisp编译顺序感到困惑。我知道如果
defmacro
内部使用了一些函数,那么这些函数应该
(eval when(:compile toplevel:load toplevel:execute))
,否则编译将失败

但是,如果宏定义和函数定义在编译时是相同的,那么顺序就很重要,对吗?宏应该位于使用它们的位置之前(如果我使用两个函数,顺序无关紧要)。我可以了解更多关于SBCL编译顺序的详细信息吗?这只适用于SBCL吗?还是按照通用Lisp的标准


谢谢大家!

顺序总是很重要的:当您想要使用宏时,必须知道它。宏执行源转换。如何使用未知宏进行源代码转换

公共Lisp标准不需要多程编译,即首先读取所有源代码并收集所有宏,然后从文件顶部开始编译。CommonLisp中的文件编译只是从头到尾地浏览源代码。以后可能会有多个编译阶段,但这将留给实现

当宏
宏测试
未知时,Lisp应该如何编译函数
测试
?Lisp编译器需要a)知道它是一个宏,b)需要有它的定义来扩展宏形式

对于通用Lisp,这是一条基本规则:

如果我们有一个表单
(foo-bar-baz)
,那么评估基本上是查看
foo

  • 如果
    foo
    是特殊运算符->使用该特殊运算符
  • 如果
    foo
    是宏运算符->宏,则展开代码并重新启动
  • 如果
    foo
    是一个函数->则使用求值参数调用该函数
  • 否则会出错
  • 编译中看起来类似:

  • 如果
    foo
    是一个特殊的操作符->编译这个特殊的表单
  • 如果
    foo
    是宏运算符->宏,则展开宏窗体并编译该代码
  • 如果
    foo
    是一个函数->编译该函数表单
  • else->warn,然后假设
    foo
    是一个函数,并编译对该名称的未来函数的调用

  • 我认为文件编译是允许的(但我认为不是必需的?)将有关未知函数的警告推迟到文件的末尾,以便像
    (defun foo(…)(bar…)这样的事情。。。(defun bar(…)…(foo…)
    可以在没有噪声的情况下编译。当然,如果一个编译器没有做到这一点,那么使用起来会很烦人@tfb:是的,编译单元中的警告已经存在,但是如果仍然有必要的话,它将在有用的时间传达给用户。在文件编译单元中,编译器可能也不会直接编译未知函数调用以使用后期绑定,但可能会等待稍后的定义…因此,假设foo是函数是函数的一个原因,如果我理解正确,函数顺序看起来无关紧要,但宏会起作用。回到
    (eval when(:compile toplevel))
    ,这意味着内部的表单在编译时会比所有其他表单先编译,对吗?@ccQpein:no,
    (eval when(:compile toplevel)…)
    意味着文件编译器在顶级查看时会对附带的表单进行评估。