从 Quicklisp 包内的宏调用函数
Calling function from macro inside Quicklisp package
我放failing.asd
(in-package :asdf-user)
(defsystem "failing"
:description "some code destined to fail"
:version "0.1"
:author "me"
:components ((:file "package")))
和package.lisp
(defpackage :failing
(:export :foo :bar))
(in-package :failing)
(defun foo () 42)
(defmacro bar ()
(let ((x (foo)))
`(print ,x)))
(bar)
变成~/quicklisp/local-projects/failing。使用安装了 Quicklisp 的 Clozure CL,我 运行
(ql:quickload :failing)
这给了我
To load "failing":
Load 1 ASDF system:
failing
; Loading "failing"
[package failing]
> Error: Undefined function FOO called with arguments () .
> While executing: BAR, in process listener(1).
> Type :GO to continue, :POP to abort, :R for a list of available restarts.
> If continued: Retry applying FOO to NIL.
> Type :? for other options.
看来我无法从包内的宏中调用函数。为什么不呢?
只有当文件在加载前被编译时才会发生这种情况。通常它与 ASDF(这是一种管理文件依赖关系和 compile/load 代码的工具)或包(它们是命名空间,与 ASDF 没有任何关系)无关。
它与 Common Lisp 中文件编译的工作方式有关:
文件编译器看到函数foo
并编译它 -> 它的代码被写入文件。 它不会 (!) 将代码加载到编译时环境中。
文件编译器然后看到宏栏并编译它 -> 代码被写入文件。 它确实 (!) 将代码加载到编译时环境中。
文件编译器然后看到宏形式(bar)
并想展开它。它调用宏函数bar
。调用 foo
,这是未定义的,因为它不在编译时环境中。
解决方案:
将函数定义放在ASDF系统中的单独文件中,compile/load更早
把函数放在宏里面作为局部函数
在函数定义周围放置(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE) ...)
。它导致定义在编译时执行。
记住:文件编译器需要知道宏函数 -> 否则它无法宏展开代码。普通函数只是编译,但在编译文件时不会在编译时加载。
我放failing.asd
(in-package :asdf-user)
(defsystem "failing"
:description "some code destined to fail"
:version "0.1"
:author "me"
:components ((:file "package")))
和package.lisp
(defpackage :failing
(:export :foo :bar))
(in-package :failing)
(defun foo () 42)
(defmacro bar ()
(let ((x (foo)))
`(print ,x)))
(bar)
变成~/quicklisp/local-projects/failing。使用安装了 Quicklisp 的 Clozure CL,我 运行
(ql:quickload :failing)
这给了我
To load "failing":
Load 1 ASDF system:
failing
; Loading "failing"
[package failing]
> Error: Undefined function FOO called with arguments () .
> While executing: BAR, in process listener(1).
> Type :GO to continue, :POP to abort, :R for a list of available restarts.
> If continued: Retry applying FOO to NIL.
> Type :? for other options.
看来我无法从包内的宏中调用函数。为什么不呢?
只有当文件在加载前被编译时才会发生这种情况。通常它与 ASDF(这是一种管理文件依赖关系和 compile/load 代码的工具)或包(它们是命名空间,与 ASDF 没有任何关系)无关。
它与 Common Lisp 中文件编译的工作方式有关:
文件编译器看到函数foo
并编译它 -> 它的代码被写入文件。 它不会 (!) 将代码加载到编译时环境中。
文件编译器然后看到宏栏并编译它 -> 代码被写入文件。 它确实 (!) 将代码加载到编译时环境中。
文件编译器然后看到宏形式(bar)
并想展开它。它调用宏函数bar
。调用 foo
,这是未定义的,因为它不在编译时环境中。
解决方案:
将函数定义放在ASDF系统中的单独文件中,compile/load更早
把函数放在宏里面作为局部函数
在函数定义周围放置
(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE) ...)
。它导致定义在编译时执行。
记住:文件编译器需要知道宏函数 -> 否则它无法宏展开代码。普通函数只是编译,但在编译文件时不会在编译时加载。