我是一个普通Lisp的初学者,我想使用一个库。
我找不到一个加载/需要/使用模块的简单示例。我安装了cl-ppcre:
$ sbcl --non-interactive --eval '(ql:quickload "cl-ppcre")'
To load "cl-ppcre":
Load 1 ASDF system:
cl-ppcre
; Loading "cl-ppcre"
..但我不知道该怎么用它。我试过以下和其他十几种东西,但没有一种有效。
$ sbcl --noinform --non-interactive --eval '(progn (require "cl-ppcre") (cl-ppcre:split "\s+" "1 2 3"))'
Unhandled SB-INT:SIMPLE-READER-PACKAGE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
{1004DB8073}>:
Package CL-PPCRE does not exist.
Stream: #<dynamic-extent STRING-INPUT-STREAM (unavailable) from "(progn (...">
Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {1004DB8073}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1003640A83}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1003640A83}>)
2: (INVOKE-DEBUGGER #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1003640A83}>)
3: (ERROR #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1003640A83}>),那么我怎样才能让它工作呢?
编辑1: --我没有建议我在使用库时遇到的问题和终端中的问题一样多。这对我来说是暗含的。这是因为我在Perl方面的经验,在Perl中,您可以在命令行完成对文件所能做的一切,包括使用库。
编辑2:这里是我的工作解决方案。事实证明,有两件事是错的。我的问题是:
使用多--eval的
就像Svante和ignis volens说的。
(load "~/.quicklisp/setup.lisp")我在这里解释说:
Confused about ql:quickload and executable scripts in SBCL
这是终端解决方案:
sbcl --non-interactive --eval '(load "~/.quicklisp/setup.lisp")' --eval '(require :cl-ppcre)' --eval '(princ (cl-ppcre:split "\\s+" "1 2 3"))'请注意,在stderr上输出了一堆警告,比如这个,我不知道为什么会这样。
WARNING: redefining QL-SETUP:QMERGE in DEFUN这是脚本解决方案:
#!/usr/bin/sbcl --script
(load "~/.quicklisp/setup.lisp")
(require :cl-ppcre)
(princ (cl-ppcre:split "\\s+" "1 2 3"))
(terpri)发布于 2022-03-29 15:00:17
这是人们对CL存在的一个常见问题的一个实例。
CL (和其他Lisps)的工作方式分为三个阶段(实际上超过三个阶段,但三个阶段就足够了):
通常,这个过程被迭代来处理,比如一个文件,或者一个输入流。
重要的是(1)、(2)和(3)依次发生:(1)在(2)开始之前完成,(1)和(2)在(3)开始之前都完成。
这意味着,(1)在(2)或(3)中发生的任何事情发生之前,必须是可能的。
因此,考虑一下这个表格:
(progn
(ql:quickload "cl-ppcre")
(cl-ppcre:split "\s+" "1 2 3"))(这几乎是您要评估的表单之一。)
所以问题是:(1)发生什么事?嗯,这需要两件事:
ql:quickload;
QL包(本质上是一个名称空间:有关“包”在CL中的含义的更多信息)必须存在才能读取QL CL-PPCRE包才能读取cl-ppcre:split.现在您看到了问题:(ql:quickload "cl-ppcre")创建了CL-PPCRE包,直到(3)才会发生这种情况。这意味着这个表单无法阅读。
在绝望中,你可以用各种各样的英雄伎俩来绕过这一切。但是,您实际上并不需要这样做:您可以做一些其他的事情(几乎如下所示):
(ql:quickload "cl-ppcre")
(cl-ppcre:split "\s+" "1 2 3")这几乎没问题,因为它不是一种形式,而是两种形式。因此,(1)-(3)对第一种形式工作良好,然后(1)-(3)为第二种形式工作良好。
所以,答案是不要试图把所有的东西都打包成一个单一的形式。要么将内容放入文件中(可能是最好的方法),要么如果您真的希望将其作为命令行参数运行,则需要安排表单是分开的,例如,使用多个--eval选项。
上面我说过,第二种,多种形式,版本几乎可以工作。而且它几乎只起作用。其原因是文件编译。让我们假设我有一个文件,其内容是:
(ql:quickload "cl-ppcre")
(cl-ppcre:scan ...)
...那么,编译器在编译该文件时会做什么呢?它按表单读取它,但通常它并不实际执行代码(有例外):它安排在加载文件时执行该代码。因此编译器不会加载compiler :它将安排生命,以便在加载文件时加载compiler。现在我们有了一个相同问题的版本:编译器无法读取第二种形式,因为CL-PPCRE包还不存在。
对此,有一个解决方案:您可以告诉编译器,实际上它必须在编译时执行一些代码:
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload "cl-ppcre"))
(cl-ppcre:scan ...)
...现在编译器知道,多亏了eval-when表单,它必须调用ql:quickload。它将这样做,因此CL-PPCRE包将在编译时定义,并且一切都会很好。
关于CL中的包裹的说明
令人遗憾的是,CL中的“package”一词的含义与许多其他语言中的含义不同:这是历史的原因,现在无法改变。
在常用的情况下,包是“可以安装的代码块,并且可能依赖于其他包(代码块),所有这些都可能由某种类型的包管理器负责。您可以在Ubuntu上安装conda作为包,或者使用包管理器来管理科学的Python包(包括Python本身)。”
在CL中,包本质上是一个命名空间。如果我键入'foo:bar‘,那么这是指包中可用的名为BAR的符号,其中一个名称或昵称是FOO。此外,这是一个“外部”的符号,这意味着它打算在某种程度上公开。包是CL中的真实对象,可以通过程序进行推理。始终有一个当前包的概念,该包定义了哪些名称是可用的,而不需要包前缀,方法是直接包含一些名称,还包含其他包的搜索(“使用”)列表。在CL中有很多软件包:比我在这里提到的要多得多。
通常被称为包的东西在CL中最好被称为“库”:它们是可以安装的代码块,并且可能本身就有依赖关系。或者,它们通常被称为“系统”,因为它们通常是使用“系统定义”工具定义的。“图书馆”可能是个更好的词:“系统”又是一个历史上的怪事,现在还不能改变。
发布于 2022-03-29 08:44:21
从bash参数作为源运行程序并不是最简单的启动方式。问题在于编译、加载和执行的顺序。大致上,您在命令行中输入的部分首先编译,然后加载,但它需要先加载库,然后才能编译其馀部分。这可能是解决这个问题的方法,例如使用多个-e参数,但我认为对于初学者来说,这并不是一个有用的练习。
如果您只想从命令行中尝试,那么在没有参数的情况下启动SBCL,这将为您提供一个REPL提示符。这是一个接受Lisp代码的命令行。它看起来像*在香草SBCL。
[user@home]> sbcl
This is SBCL …
*在该提示符下,加载库:
* (ql:quickload "cl-ppcre")
To load "cl-ppcre":
Load 1 ASDF system:
cl-ppcre
; Loading "cl-ppcre"
[package cl-ppcre]................................
..........................
("cl-ppcre")
* 然后使用它:
* (cl-ppcre:split "\s+" "1 2 3")
("1 2 3")
* 然后可以退出REPL:
* (quit)
[user@home]>对于严肃的工作,使用文件。
发布于 2022-03-29 19:26:21
包
定义
库或应用程序称为system.
中。
:BAR表示包FOO中名为BAR的符号。
FOO:BAR表示包FOO中导出的名为BAR的符号。
栏表示当前包中的符号条。
若要读取带有特定包的符号,则该包需要存在。
示例:
在LispWorks中有一个名为CAPI ->的包,我们可以找到它。
CL-USER 44 > (find-package "CAPI")
#<The CAPI package, 5109/8192 internal, 880/1024 external>
CL-USER 45 > (read-from-string "CAPI::BAR")
CAPI::BAR
9上面在现有的包CAPI中创建一个名为BAR的符号。
但是没有一个叫FOO的包裹。我们找不到它:
CL-USER 46 > (find-package "FOO")
NIL现在读取包FOO中的符号是一个错误,因为包不存在:
CL-USER 47 > (read-from-string "FOO::BAR")
Error: Reader cannot find package FOO.
1 (continue) Create the FOO package.
2 Use another package instead of FOO.
3 Try finding package FOO again.
4 (abort) Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 48 : 1 > 问题
当您有一个Lisp表单时,您需要确保它不包含未知的包。因此,首先用软件加载系统,该软件也定义了包。然后在包cl-ppcre:split split中找到符号cl-ppcre
(progn
(ql:quickload "cl-ppcre")
(funcall (find-symbol "SPLIT" "CL-PPCRE") "\\s+" "1 2 3"))上面避免提到符号cl-ppcre:split。相反,我们通过find-symbol在运行时查找它。
或者:
(progn
(ql:quickload "cl-ppcre")
(eval (read-from-string "(cl-ppcre:split \"\\\\s+\" \"1 2 3\")")))或者:把它变成两种形式:
(ql:quickload "cl-ppcre") ; loading the software
; also creates the package CL-PPCRE
(cl-ppcre:split "CL-PPCRE") "\\s+" "1 2 3"))https://stackoverflow.com/questions/71657797
复制相似问题