repl 和编译文件之间的 lisp 包差异
我目前正在 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 包,但在编译文件时却找不到?
I'm currently playing with lispbuilder-sdl on SBCL under Windows.
My source code is as follows:
(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)
When I compile the file I get the error: package "SDL-EXAMPLES" not found.
If I remove the (sdl-examples:squashed) from the file it compiles ok. I can then type (sdl-examples:squashed) at the repl and the demo game starts fine.
Why is the sdl-examples package found from the repl but not when I compile the file?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
该文件的所有编译都发生在执行任何
load-op
之前。因此,当 Lisp 编译(sdl-examples:squashed)
行时,它尚未运行定义包的load-op
。您可以通过不提及
sdl-examples
包来解决这个问题,该包要求读者在load-op
实际执行之前找到其squashed
符号。执行:这个想法是从其符号名称计算包,查找命名函数的符号,并获取它命名的函数 - 但这种方式要求包仅在代码运行时存在,而不是在第一次读取时存在。然后,您的四个语句都可以被编译,按顺序执行,并且在执行最后一个语句时,您的加载操作将创建包。
因此,这里有更多有关此处发生的情况的信息:
'#:some-name
引用不属于任何包的符号。这样我们就可以引用一个符号名称,而不必(1)假设它的包存在或(2)用该名称破坏其他包。'(symbol-name #:some-name)
将符号名称提取为字符串。为什么不直接写“some-name”
?你可以,而且通常会起作用。但对于运行“现代模式”区分大小写的 Lisp 来说,这种方式更加稳健。find-package
将字符串名称映射到 Lisp 的包表示形式。请记住,当您运行此行时,您的包将存在。intern
返回给定包中具有给定名称的符号。symbol-function
返回与符号关联的函数对象(一个 lambda 抽象,或更可能是其编译后的表示)。它有点笨重,但不幸的是,没有真正更好的方法来混合加载代码的调用来创建一个包,该包的名称位于同一文件中的该包中。
All of the compilation of that file happens before executing any of the
load-op
s. So when Lisp compiles the(sdl-examples:squashed)
line, it hasn't run theload-op
that defines your package.You can get around this by not mentioning the
sdl-examples
package that requires the reader to locate itssquashed
symbol before theload-op
is actually executed:The idea is to calculate the package from its symbolic name, lookup the symbol naming your function, and fetch the function it names - but this way requires that the package exist only when the code is run, not when it is first read. Then your four statements can all be compiled, executed in order, and by the time that last statement is executed, your
load-op
s will have created the package.So here's a little more info about what's happening here:
'#:some-name
refers to a symbol that's not part of any package. So that way we can make a reference to a symbolic name without either (1) assuming its package exists or (2) mucking up some other package with the name.'(symbol-name #:some-name)
extracts the name of the symbol as a string. Why not just write"some-name"
? You could, and it will usually work. But this way is a little more robust for the case of running a "modern-mode" case-sensitive Lisp.find-package
maps a string name to Lisp's representation of a package. Remember, by the time you run this line, your package will exist.intern
returns the symbol with the given name that lives in the given package.symbol-function
returns the function object (a lambda abstraction, or more likely, its compiled representation) associated with the symbol.funcall
invokes that function.It is kind of clunky, but unfortunately there's not really a better way to mix calls which load code to create a package with names living in that package in the same file.