关于Common Lisp编译顺序的问题

问题描述 投票:0回答:1

我在一个文件中这样写了一个宏和一个函数:

(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))

然后我在repl中加载此文件并运行(test)。我收到此错误:

The variable REAL-B is unbound.

但是,当我放defmacro 之前 defun时。一切都很好。

我对通用的Lisp编译顺序感到困惑。我知道defmacro内部是否使用了某些功能,这些功能应为(eval-when (:compile-toplevel :load-toplevel :execute)),否则编译将失败。

但是,如果宏定义和函数定义在编译时相同,则顺序很重要,对吗?宏应该位于使用它们的位置(如果我做两个函数,顺序无关紧要)。我可以详细了解SBCL的编译顺序吗?而且仅适用于SBCL吗?还是使用Common Lisp的标准?

谢谢!

lisp common-lisp sbcl
1个回答
0
投票

顺序总是很重要:当您要使用宏时,必须知道它。

当宏test未知时,Lisp应该如何编译函数macro-test? Lisp编译器需要a)知道它是一个宏,并且b)需要有其定义才能扩展宏形式。

对于Common Lisp,这是一个基本规则:

[如果我们有(foo bar baz)形式,则评估基本上看foo

  1. 如果foo是特殊运算符->使用该特殊运算符
  2. 如果foo是宏运算符->宏展开代码,然后重新开始
  3. 如果foo是一个函数->使用已评估的参数调用该函数
  4. 其他->错误

在编译中看起来很相似:

  1. 如果foo是特殊运算符->编译该特殊运算符
  2. 如果foo是宏运算符->宏,展开代码并编译该代码
  3. 如果foo是一个函数->编译该函数调用
  4. 否则->警告,然后假定foo是一个函数,并编译对该名称的将来函数的调用
© www.soinside.com 2019 - 2024. All rights reserved.