【问题标题】:Calling function from macro inside Quicklisp package从 Quicklisp 包中的宏调用函数
【发布时间】:2015-06-09 03:05:08
【问题描述】:

我把 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.

似乎我无法从包内的宏中调用函数。为什么不呢?

【问题讨论】:

    标签: macros lisp common-lisp quicklisp


    【解决方案1】:

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

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

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

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

    文件编译器然后看到(bar) 的宏形式并想要扩展它。它调用宏函数bar。它调用foo,这是未定义的,因为它不在编译时环境中。

    解决方案

    • 将函数定义放在ASDF系统的单独文件中,并提前编译/加载。

    • 将函数作为局部函数放入宏中

    • 在函数定义周围加上(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE) ...)。它导致定义在编译时执行。

    记住文件编译器需要知道宏函数 -> 否则它将无法对代码进行宏扩展。普通函数只是在编译文件期间被编译,而不是在编译时加载。

    【讨论】:

    • 谢谢,解决了我的问题。作为一个附带问题,为什么 Common Lisp 中的包如此复杂?直觉上我想,当我想编写模块化代码时,我只是将其拆分为文件,然后导入正确的文件。这就是它发生在例如Python。 Common Lisp 的 DNA 中有什么东西让这成为不可能吗?
    • @slimetree:我们正在讨论宏和文件编译的结合。香草蟒不提供。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多