2

我目前正在 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 包,但在我编译文件时却没有?

4

1 回答 1

2

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

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

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

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


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

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