5

我在 Debian Squeeze 上使用 SBCL 1.0.56,带有 cl-swank/slime 1:20120420-2(Debian 版本号)。这些都是当前不稳定的版本。

我在加载第三方 CL 包时遇到了问题。在 Debian 上使用 CL 的文档(实际上是在 Linux 上更通用的 CL 使用文档)是粗略的、矛盾的和过时的,所以我将总结一下我所知道的。这就是我所在的地方。

Debian 在 /usr/share/common-lisp/source. 在拆分序列的情况下,这是 /usr/share/common-lisp/source/cl-split-sequence.

.asd 文件(这里 /usr/share/common-lisp/source/cl-split-sequence/split-sequence.asd),据我了解,它为 CL 实现提供有关版本和依赖项的说明,看起来像

;;; -*- Lisp -*- mode
(defpackage #:split-sequence-system (:use #:cl #:asdf))
(in-package :split-sequence-system)

(defsystem :split-sequence
    :version "20011114.1"
    :components ((:file "split-sequence")))

现在,在运行 slime 时,在 REPL 中输入以下两行可以正常工作

(require :split-sequence)
(split-sequence:SPLIT-SEQUENCE  #\, "foo,bar")

调用(我认为)SBCL 内的 ASDF的(require :split-sequence)内置副本,它可能看起来是split-sequence.asd. 这可能是特定于 SBCL 的,请参阅Debian 手册第 3 章 -Libraries 中的 Common Lisp。值得注意的是,这个页面和我遇到的任何东西一样有用和详细,它经常提到 CLC(Common Lisp Controller),但似乎 Debian 正在远离这个。请参阅 Redesign of Common Lisp Controller,我不完全理解。无论如何,没有一个记录在案的使用 CLC 的命令对我有用。但是,CLC 在 Debian 上仍然可用。此外,用户邮件列表已失效 - 请参阅Clc-users 档案

第一次(require :split-sequence)被调用,它被编译,并且(在我的系统上,可能是 Debian 特定的)结果fasl被放置在

~/.cache/common-lisp/sbcl-1.0.56.0.debian-linux-x86/usr/share/common-lisp/source/cl-split-sequence/split-sequence.fasl

即文件被放置在文件系统中的缓存下,镜像原始源的位置。显而易见的问题是,系统如何知道去哪里寻找包裹?这是我不确定的一件事。看起来搜索路径应该在 /etc/common-lisp/source-registry.conf.dASDF Debian 软件包的一部分中给出,但最接近的 01-common-lisp-controller.conf

(:directory  #p"/usr/share/common-lisp/systems/")

也许这在某个地方是硬连线的,但我想知道。

无论如何,一旦这个 ASDF 文件在缓存中,它就不会再次编译,但是 REPL 在 slime 启动后看不到它,除非 require再次编译。

现在,如果我把线

(require :split-sequence)
(split-sequence:SPLIT-SEQUENCE  #\, "foo,bar")

在一个文件中,比如说seq.lisp,并用 Cc Ck 将它加载到 REPL 中,我得到一个错误和回溯,从

The name "SPLIT-SEQUENCE" does not designate any package.
   [Condition of type SB-KERNEL:SIMPLE-PACKAGE-ERROR]

所以我得出结论,包没有正确加载。我尝试了类似的变化

(asdf:oos 'asdf:load-op :split-sequence)

(asdf:load-system :split-sequence)

但没有骰子。奇怪的是,假设我们只有这条线

(require :split-sequence)

在一个文件中 -require.lisp为清楚起见调用它。然后加载 require.lisp不报错,然后输入

(split-sequence:SPLIT-SEQUENCE  #\, "foo,bar")

在 REPL 工作!但是,如果不加载require.lisp,则在 REPL 中键入前一行是行不通的。

因此,总而言之,如何在脚本中成功加载包?我也对上面提到的问题感兴趣,关于 ASDF 如何找到/usr/share/common-lisp/source/位置,但这更多是一个附带问题。

4

2 回答 2

5

C-c C-k编译源文件,然后加载编译后的文件。

Lisp 源文件包含定义和调用。文件编译器遍历文件并为其创建代码。但它不执行它。

如果您的文件包含对 的调用REQUIRE,则它不会在编译期间执行。如果您稍后加载已编译的文件,它将被执行。如果文件中的下一个 Lisp 表单正在使用调用后可用的某个包REQUIRE,则它在编译期间不存在,因为REQUIRE尚未执行 - 因此在编译时读取错误。

基本上有两种解决方案:

  • REQUIRE在使用所需功能编译特定文件之前执行所有必要的操作。
  • REQUIRE在编译期间执行语句。这就是EVAL-WHEN :COMPILE-TOPLEVEL告诉编译器在编译期间执行子表单的地方。

#+:sbcl(foo)表示 (foo) 仅:SBCL在 list 中存在符号时才被读取CL:*FEATURES*。使用它是为了让编译器仅在它是 SBCL 时才能看到此代码。

Common Lisp 代码的编译需要更仔细的准备,因为:

  • 可以在文件编译期间执行 Lisp 代码,从而改变文件编译器的行为。

  • 文件编译器的读者需要知道源代码中使用的包(它们是符号的命名空间)。

于 2012-05-11T06:30:51.253 回答
1

我遇到了以下帖子,Zach Beane 的博客 - 制作一个小型 Common Lisp 项目,其中包含指向http://common-lisp.net/~loliveira/ediware/ediware.lisp的链接

复制该文件顶部的代码是可行的。所以在这个文件上运行 Cc Ck 在 slime 中split-sequence,并运行代码int (split-sequence:SPLIT-SEQUENCE #\, "foo,bar"))

#+:sbcl
(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :asdf))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (asdf:oos 'asdf:load-op :split-sequence))

(defpackage #:seq
  (:use #:cl #:split-sequence))
(in-package #:seq)

(print (split-sequence:SPLIT-SEQUENCE  #\, "foo,bar"))

但是,我不知道这些神奇的咒语是做什么的。有人愿意解释一下吗,也许在另一个答案中?我把它放在一个答案中,因为它是问题的答案,但它并不完整,因为我不明白它为什么起作用。我很乐意接受对此脚本的解释。

于 2012-05-11T06:19:06.877 回答