Common Lisp
Common Lisp 是一种高度动态、多范式语言,强调交互性和性能。由于完全标准化,有多个独立的实现可供选择。
安装
sbcl (http://www.sbcl.org/) 是最流行的 FOSS 实现,并且通常在整个生态系统中具有最高的兼容性。它的编译器生成原生机器代码,并且该项目每月发布版本。
它在 Lisp 中于 ~/.sbclrc
内配置,但您可能不需要这个,具体取决于您选择的依赖管理策略。
其他实现
还有许多其他可用的实现。除了以下选项外,还有两个主要的商业 Lisp 实现,Allegro 和 LispWorks,但它们具有严格的许可条款,并且未在 Arch Linux 生态系统中打包。
活跃
这些实现与现代工具无缝协作,可用于严肃的项目。
- ABCL — Armed Bear Common Lisp:在 Java 虚拟机上运行。
- CCL — Clozure Common Lisp:基于 Open Macintosh Common Lisp,以编译速度快而闻名。
- https://ccl.clozure.com/ || cclAUR
- Clasp — Clasp:一种较新的 Common Lisp 实现,可与 C++ 库互操作,并使用 LLVM 进行编译为原生代码。
- ECL — Embeddable Common Lisp:编译为 C 代码,从而提供良好的 C 集成和可嵌入性。
历史
虽然这些实现有软件包可用,但库和工具的兼容性有时值得怀疑,并且某些实现不再积极维护。
- CLISP — ANSI Common Lisp 解释器、编译器和调试器:提供良好的 C 集成和可嵌入性。
- CMUCL — CMU Common Lisp:最初在卡内基梅隆大学开发的仅 POSIX 实现。
- GCL — GNU Common Lisp:Kyoto Common Lisp 在 80 年代的后代,也是 ECL 的同级。
- MKCL — Mankai Common Lisp:Kyoto Common Lisp 的类似后代。
依赖管理
Common Lisp 中的依赖管理传统上涉及 Quicklisp,但在最近几年,现代替代方案已经出现。
Vend
Vend 是一个简单的工具,用于直接在项目仓库中下载和访问依赖项。它不需要任何特殊配置。
安装 vendAUR 包后,您可以从项目的顶层目录运行 vend get
[vend] Downloading dependencies. [vend] Fetching FN-MACRO [vend] Fetching ARROW-MACROS [vend] Fetching TRANSDUCERS ... [vend] Done.
之后,vend repl
将启动 REPL 会话。
编辑器集成
Emacs
对于 Sly/Slime 的 Emacs 用户,可以通过以下方式配置编辑器内 REPL
(setq sly-default-lisp 'sbcl sly-lisp-implementations '((sbcl ("vend" "repl" "sbcl") :coding-system utf-8-unix) (ecl ("vend" "repl" "ecl") :coding-system utf-8-unix)))
您可以自由地以类似的方式添加其他编译器。根据 Slime 的需要进行调整。
Lem
Lem 用户可以使用以下命令打开 REPL
C-u M-x slime <RET> vend repl
Vim
与支持多个正在运行的 Lisp 的 Emacs 不同,Slimv 需要一个独立服务器,该服务器在 Vim 重启后仍然存在。
如果我们希望 Slimv 可以看到 vendored/
中的依赖项,我们必须从项目目录手动启动其服务器
> cd project/ > vend repl ecl --load /home/YOU/.vim/pack/common-lisp/start/slimv/slime/start-swank.lisp
现在,Vim 中的 ,c
(REPL 连接) 将自动找到正在运行的服务器,您可以加载项目和 vendored/
中可用的任何系统。
如果要切换项目,您需要手动退出 REPL 服务器并如上所述重新启动它。您可能还希望为上面显示的长调用设置 shell 别名或创建包装脚本。
OCICL
OCICL 是 Quicklisp 的现代替代品,它将软件包作为来自中央软件包仓库的 OCI 兼容工件 分发。与 Quicklisp 类似,它必须由用户配置以接管和管理依赖项加载。
安装 ociclAUR 后,运行 ocicl setup
,这会将以下内容添加到您的编译器配置文件中
#-ocicl (when (probe-file #P"/home/green/.local/share/ocicl/ocicl-runtime.lisp") (load #P"/home/green/.local/share/ocicl/ocicl-runtime.lisp")) (asdf:initialize-source-registry (list :source-registry (list :directory (uiop:getcwd)) :inherit-configuration))
现在,在 REPL 中,任何尝试在未知依赖项上运行 (asdf:load-system :foo)
的操作都将自动下载它。进一步的项目配置是通过 systems.csv
文件完成的,您需要将该文件提交到项目仓库。有关更多设置和使用详情,请参阅 README。
Quicklisp
Quicklisp 是将库获取和加载到 Common Lisp 程序中的原始方法。默认情况下,它有一个由机器上所有程序共享的单个全局包缓存,并且它从一个保守更新的仓库(也可能令人困惑地称为 Quicklisp)中拉取包。
安装 quicklisp 包后,可以按如下方式为特定编译器注册它
> sbcl --load /usr/share/quicklisp/quicklisp.lisp * (quicklisp-quickstart:install) * (ql:add-to-init-file)
之后,可以在所有未来的 REPL 会话中使用 (ql:quickload "foo")
来加载依赖项,并在必要时下载它。
要更新通过 Quicklisp 安装的所有软件包,请在 REPL 中运行以下命令
(ql:update-all-dists)
~/common-lisp/
下。这对于 Vend 和 OCICL 等其他方法并非如此。Ultralisp
Ultralisp 是一个备用的 Quicklisp 仓库,它提供所有软件包的滚动发布版本,通常与 Github 等上可用的版本同步更新。
要注册它,请在 REPL 中运行以下命令
(ql-dist:install-dist "http://dist.ultralisp.org/" :prompt nil)
然后,如果您通过 ql:quickload
加载的软件包在 Ultralisp 中更新,它将从那里加载而不是从 Quicklisp 加载。
Qlot
或者,如果您对 Quicklisp 没问题,但想要项目本地依赖项,则可以使用 Qlot (qlotAUR)。
安装完成后,可以通过以下方式初始化项目仓库以使用它
qlot init
自定义依赖
使用 Qlot,所有自定义依赖项位置都在 qlfile
中声明。例如,要声明 Ultralisp 的使用,只需添加
dist http://dist.ultralisp.org
或者指定对本地文件系统上依赖项的依赖
local foobar /home/you/code/common-lisp/foobar
有关更多选项,请参阅 Qlot 的 README。
要安装声明的依赖项,请运行
qlot install
调用 REPL
要加载具有当前 Qlot 环境的 REPL,请运行
qlot exec sbcl
对于 Sly/Slime 的 Emacs 用户,请考虑如何通过以下方式启动编辑器内 REPL
(setq sly-default-lisp 'qlot-sbcl sly-lisp-implementations '((qlot-sbcl ("qlot" "exec" "sbcl") :coding-system utf-8-unix)))
根据 Slime 的需要进行调整。
开发环境
Emacs
Common Lisp 开发通常在 Emacs 中完成,通过 slime 或较新的 sly。两者都在社区中被广泛采用,并具有类似的使用界面。
Portacle
Portacle 是一个基于 Emacs 的一体化 Common Lisp 开发环境。其目的是让初学者轻松入门 Lisp。
Lem
Lem (lem-editor-gitAUR) 是一款较新的编辑器,风格类似于 Emacs,但完全用 Common Lisp 编写和配置。它具有终端和 GUI 前端,并支持多种语言。
Vim
Slimv 是从 Emacs 移植的 Slime 版本,它利用 Slime 的 Swank 后端服务器,提供与 Emacs 非常相似的体验。要手动安装插件
mkdir -p ~/.vim/pack/common-lisp/start cd ~/.vim/pack/common-lisp/start git clone --depth 1 https://github.com/kovisoft/slimv.git
重启 Vim 并打开一个 Common Lisp 文件。Slimv 应该处于活动状态,,c
将启动 REPL 服务器并将您连接到它。
VSCode
VSCode 对 Common Lisp 的支持在编辑器中最弱,但仍然是可能的。Alive 插件充当完整的开发环境,并带有自己的 LSP,这需要手动安装。
提示
管理 Init 文件
库作者经常使用多个编译器实现来测试他们的代码。但是,每个实现都有自己唯一命名的 init 文件,例如 .sbclrc
或 .eclrc
,但这些文件的内容通常是相同的。与其为每个编译器手写这些文件,不如创建一个主文件并将其他文件符号链接到它。例如,如果您认为 .sbclrc
是您的“主配置文件”,那么
ln -s /home/you/.sbclrc .eclrc ln -s /home/you/.sbclrc .abclrc
等等。主要的 init 文件有
~/.sbclrc # for SBCL ~/.abclrc # for ABCL ~/.ccl-init.lisp # for CCL ~/.clasprc # for CLASP ~/.eclrc # for ECL ~/.clisprc.lisp # for CLISP ~/.cmucl-init.lisp # for CMUCL ~/.mkclrc # for MKCL ~/.clinit.cl # for Allegro
减少编译输出的冗余信息
特别是 SBCL 可能会非常热衷于输出大量编译器“notes”。要静默这些 notes,同时仍然显示通常的错误和警告,请在您的 ~/.sbclrc
中设置以下内容
(declaim (sb-ext:muffle-conditions sb-ext:compiler-note))
故障排除
Quicklisp 无法加载本地项目
(ql:quickload "...")
用于加载外部依赖项和本地项目。但是,如果您的本地项目未位于 ~/common-lisp/
下,则它将无法加载(或者甚至可能从在线拉取,如果您已发布它)。
实际上,Quicklisp 只是在获取和组织软件包。在内部,它使用 ASDF 构建系统来实际加载它们。也可以加载任何本地项目或您已通过 (asdf:load-system "foo")
下载的软件包,默认情况下,ASDF 仅在 ~/common-lisp/
中查找本地项目。
虽然可以配置,但一个更简单的方法是使用符号链接
ln -s /home/you/code/common-lisp/ common-lisp
(asdf:load-package "foo")
就会“正常工作”。什么是项目、系统和包?
本文的其余部分以“包”这个术语在其他编程语言中通常使用的方式来使用,与“库”同义。然而,尽管在 90 年代中期标准化,但 Common Lisp 的最早形式可以追溯到 80 年代,因此涉及项目管理的术语有所不同。本质上
- 项目:一组系统。在其他语言中有时称为“工作区”。
- 系统:一组包。这些可以代表库和“可执行文件”。
- 包:一组函数和类型定义。在其他语言中通常称为“模块”,但可以跨越多个文件。
正如你所看到的,在其他地方通常被称为库(library)的东西在 Common Lisp 中被称为 “系统”(system)。因此得名 asdf:load-system
。 点击这里查看 一个相互依赖的多系统项目的例子。
另请参阅
- Common Lisp 文档 现代化的在线文档。
- 社区规范:更多在线标准库文档。
- Common Lisp 烹饪书:关于许多主题的 HOWTO 指南。
- Awesome CL:生态系统概览。
- Quickdocs:Quicklisp 库查找。
- Portability:编译器实现兼容性列表。
- 维基百科:Common Lisp
- Cliki:Common Lisp Wiki