【问题标题】:lisp package differences between repl and compile filelisp包repl和编译文件的区别
【发布时间】:2011-04-03 08:58:52
【问题描述】:

我目前正在 Windows 下的 SBCL 上使用 lispbuilder-sdl。

我的源码如下:

(asdf:operate 'asdf:load-op :lispbuilder-sdl)
(asdf:operate 'asdf:load-op :lispbuilder-sdl-binaries)
(asdf:operate 'asdf:load-op :lispbuilder-sdl-examples)
(sdl-examples:squashed)

编译文件时出现错误:找不到包“SDL-EXAMPLES”。

如果我从文件中删除 (sdl-examples:squashed) ,它可以编译。然后我可以在 repl 中键入 (sdl-examples:squashed) 并且演示游戏开始正常。

为什么我从repl中找到了sdl-examples包,而我编译文件时却没有?

【问题讨论】:

    标签: lisp package read-eval-print-loop


    【解决方案1】:

    该文件的所有编译都发生在执行任何load-ops 之前。所以当 Lisp 编译 (sdl-examples:squashed) 行时,它并没有运行定义你的包的 load-op

    您可以通过不提及sdl-examples 包来解决此问题,该包要求读者在实际执行load-op 之前找到其squashed 符号:

    (funcall (symbol-function (intern (symbol-name '#:squashed)
                                      (find-package (symbol-name '#:sdl-examples)))))
    

    这个想法是从它的符号名称计算包,查找命名你的函数的符号,并获取它命名的函数 - 但这种方式要求包仅在代码运行时存在,而不是在第一次读取时存在.那么你的四条语句就可以全部编译,依次执行,到最后一条语句执行完毕,你的load-ops就已经创建了包了。


    所以这里有更多关于这里发生的事情的信息:

    • '#:some-name 指的是不属于任何包的符号。这样我们就可以引用一个符号名称,而无需 (1) 假设它的包存在或 (2) 用该名称混淆其他一些包。
    • 然后'(symbol-name #:some-name) 将符号名称提取为字符串。为什么不直接写"some-name"?你可以,而且它通常会起作用。但是对于运行“现代模式”区分大小写的 Lisp 来说,这种方式更加稳健。
    • find-package 将字符串名称映射到 Lisp 的包表示形式。请记住,当您运行此行时,您的包将存在。
    • intern 返回给定包中具有给定名称的符号。
    • symbol-function 返回与符号关联的函数对象(一个 lambda 抽象,或者更可能是它的编译表示)。
    • 然后funcall 调用该函数。 这有点笨拙,但不幸的是,没有更好的方法来混合调用,这些调用加载代码来创建一个包,该包中的名称存在于同一文件中。

    【讨论】:

    • 感谢您的回复。这有点超出了我对 lisp 的理解。我是一只年轻的蚱蜢,需要上蜡。当我运行它时,符号函数说它只需要一个参数。如何将包对象连接到符号字符串?我假设这就是问题所在。
    • 哎呀!我的错 --- 忘记调用 intern 将函数名称和封装粘合在一起。现已编辑更正。
    • 非常感谢您的解释。这有助于我理解什么符号以及编译和运行时间的区别。我假设如果我要开始编写一个真正的应用程序,可以通过在单独的 asd 文件中定义代码来避免这种不愉快?
    • @Giles Roberts 是的,这就是我的建议。然后,当您加载(或编译)您的包时,ASDF 将确保您所依赖的系统已加载(并在必要时进行编译)。
    • 谢谢。有一分钟我觉得我的眼睛很有趣,但它只是语法错误地突出显示 lisp 代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 2013-12-18
    • 2013-06-24
    • 2015-03-20
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    相关资源
    最近更新 更多