我目前正在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包,但在编译文件时却找不到?
答案 0 :(得分:2)
该文件的所有编译都在执行任何load-op
之前发生。因此,当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
将创建包。
所以这里有关于这里发生了什么的更多信息:
'#:some-name
指的是不属于任何包的符号。因此,我们可以在没有(1)假设其包存在的情况下或(2)使用名称包含其他包的情况下引用符号名称。'(symbol-name #:some-name)
将符号的名称提取为字符串。为什么不写"some-name"
?你可以,它通常会起作用。但对于运行“现代模式”区分大小写的Lisp来说,这种方式更为强大。find-package
将字符串名称映射到Lisp的包表示。请记住,当您运行此行时,您的包将存在。intern
返回具有给定包名的给定名称的符号。symbol-function
返回与符号关联的函数对象(lambda抽象,或更可能是其编译表示)。funcall
调用该函数。
它有点笨重,但不幸的是,实际上并没有更好的方法来混合调用,这些调用加载代码来创建一个包含在同一文件中的包中的名称。