从Quicklisp包中的宏调用函数

5 lisp macros common-lisp quicklisp

我把失败.asd

(in-package :asdf-user)                    

(defsystem "failing"                       
  :description "some code destined to fail"
  :version "0.1"                           
  :author "me"                      
  :components ((:file "package")))         
Run Code Online (Sandbox Code Playgroud)

package.lisp

(defpackage :failing  
  (:export :foo :bar))

(in-package :failing) 

(defun foo () 42)     

(defmacro bar ()      
  (let ((x (foo)))    
    `(print ,x)))     

(bar)                 
Run Code Online (Sandbox Code Playgroud)

进入〜/ quicklisp/local-projects /失败.使用安装了Quicklisp的Clozure CL,我运行

(ql:quickload :failing)
Run Code Online (Sandbox Code Playgroud)

这给了我

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.
Run Code Online (Sandbox Code Playgroud)

看来我无法从包内的宏调用函数.为什么不?

Rai*_*wig 6

只有在加载之前编译文件时才会发生这种情况.通常它与ASDF(管理文件依赖性和编译/加载代码的工具)或包(它们是名称空间,与ASDF无任何关系)无关.

它与Common Lisp中文件编译的工作方式有关:

文件编译器看到的功能foo并对其进行编译- >它的代码被写入到文件中.它不会(!)将代码加载到编译时环境中.

然后文件编译器看到宏栏并编译它 - >代码被写入文件.它确实(!)将代码加载到编译时环境中.

然后,文件编译器会看到宏窗体(bar)并想要扩展它.它调用宏功能bar.哪些调用foo未定义,因为它不在编译时环境中.

方案:

  • 将函数定义放在ASDF系统的单独文件中,然后再编译/加载它.

  • 把函数放在宏中作为本地函数

  • 放置(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE) ...)功能定义.它导致定义在编译时执行.

记住:文件编译器需要知道宏函数 - >否则它将无法宏扩展代码.普通函数只是在编译文件时编译,但在编译时没有加载.

  • @slimetree:我们谈论的是宏和文件编译.香草蟒蛇没有提供. (2认同)