首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在通用Lisp中使用库?

如何在通用Lisp中使用库?
EN

Stack Overflow用户
提问于 2022-03-29 07:07:29
回答 5查看 382关注 0票数 1

我是一个普通Lisp的初学者,我想使用一个库。

我找不到一个加载/需要/使用模块的简单示例。我安装了cl-ppcre:

代码语言:javascript
复制
$ sbcl --non-interactive --eval '(ql:quickload "cl-ppcre")'
To load "cl-ppcre":
  Load 1 ASDF system:
    cl-ppcre
; Loading "cl-ppcre"
..

但我不知道该怎么用它。我试过以下和其他十几种东西,但没有一种有效。

代码语言:javascript
复制
$ 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说的。

  1. (load "~/.quicklisp/setup.lisp")

我在这里解释说:

Confused about ql:quickload and executable scripts in SBCL

这是终端解决方案:

代码语言:javascript
复制
sbcl --non-interactive --eval '(load "~/.quicklisp/setup.lisp")' --eval '(require :cl-ppcre)' --eval '(princ (cl-ppcre:split "\\s+" "1  2 3"))'

请注意,在stderr上输出了一堆警告,比如这个,我不知道为什么会这样。

代码语言:javascript
复制
WARNING: redefining QL-SETUP:QMERGE in DEFUN

这是脚本解决方案:

代码语言:javascript
复制
#!/usr/bin/sbcl --script

(load "~/.quicklisp/setup.lisp")
(require :cl-ppcre)

(princ (cl-ppcre:split "\\s+" "1    2 3"))
(terpri)
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2022-03-29 15:00:17

这是人们对CL存在的一个常见问题的一个实例。

CL (和其他Lisps)的工作方式分为三个阶段(实际上超过三个阶段,但三个阶段就足够了):

  1. 读取一系列字符,将其转化为形式;
  2. 各种魔术发生在该表单上;
  3. ,第2阶段的结果被评估,也许结果被打印出来。

通常,这个过程被迭代来处理,比如一个文件,或者一个输入流。

重要的是(1)、(2)和(3)依次发生:(1)在(2)开始之前完成,(1)和(2)在(3)开始之前都完成。

这意味着,(1)在(2)或(3)中发生的任何事情发生之前,必须是可能的。

因此,考虑一下这个表格:

代码语言:javascript
复制
(progn 
  (ql:quickload "cl-ppcre")
  (cl-ppcre:split "\s+" "1 2 3"))

(这几乎是您要评估的表单之一。)

所以问题是:(1)发生什么事?嗯,这需要两件事:

ql:quickload;

  • the

  • QL包(本质上是一个名称空间:有关“包”在CL中的含义的更多信息)必须存在才能读取QL CL-PPCRE包才能读取cl-ppcre:split.

现在您看到了问题:(ql:quickload "cl-ppcre")创建了CL-PPCRE包,直到(3)才会发生这种情况。这意味着这个表单无法阅读。

在绝望中,你可以用各种各样的英雄伎俩来绕过这一切。但是,您实际上并不需要这样做:您可以做一些其他的事情(几乎如下所示):

代码语言:javascript
复制
(ql:quickload "cl-ppcre")
(cl-ppcre:split "\s+" "1 2 3")

这几乎没问题,因为它不是一种形式,而是两种形式。因此,(1)-(3)对第一种形式工作良好,然后(1)-(3)为第二种形式工作良好。

所以,答案是不要试图把所有的东西都打包成一个单一的形式。要么将内容放入文件中(可能是最好的方法),要么如果您真的希望将其作为命令行参数运行,则需要安排表单是分开的,例如,使用多个--eval选项。

上面我说过,第二种,多种形式,版本几乎可以工作。而且它几乎只起作用。其原因是文件编译。让我们假设我有一个文件,其内容是:

代码语言:javascript
复制
(ql:quickload "cl-ppcre")
(cl-ppcre:scan ...)
...

那么,编译器在编译该文件时会做什么呢?它按表单读取它,但通常它并不实际执行代码(有例外):它安排在加载文件时执行该代码。因此编译器不会加载compiler :它将安排生命,以便在加载文件时加载compiler。现在我们有了一个相同问题的版本:编译器无法读取第二种形式,因为CL-PPCRE包还不存在。

对此,有一个解决方案:您可以告诉编译器,实际上它必须在编译时执行一些代码:

代码语言:javascript
复制
(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中最好被称为“库”:它们是可以安装的代码块,并且可能本身就有依赖关系。或者,它们通常被称为“系统”,因为它们通常是使用“系统定义”工具定义的。“图书馆”可能是个更好的词:“系统”又是一个历史上的怪事,现在还不能改变。

票数 4
EN

Stack Overflow用户

发布于 2022-03-29 08:44:21

从bash参数作为源运行程序并不是最简单的启动方式。问题在于编译、加载和执行的顺序。大致上,您在命令行中输入的部分首先编译,然后加载,但它需要先加载库,然后才能编译其馀部分。这可能是解决这个问题的方法,例如使用多个-e参数,但我认为对于初学者来说,这并不是一个有用的练习。

如果您只想从命令行中尝试,那么在没有参数的情况下启动SBCL,这将为您提供一个REPL提示符。这是一个接受Lisp代码的命令行。它看起来像*在香草SBCL。

代码语言:javascript
复制
[user@home]> sbcl
This is SBCL …
*

在该提示符下,加载库:

代码语言:javascript
复制
* (ql:quickload "cl-ppcre")
To load "cl-ppcre":
  Load 1 ASDF system:
    cl-ppcre
; Loading "cl-ppcre"
[package cl-ppcre]................................
..........................
("cl-ppcre")
* 

然后使用它:

代码语言:javascript
复制
* (cl-ppcre:split "\s+" "1 2 3")
("1 2 3")
* 

然后可以退出REPL:

代码语言:javascript
复制
* (quit)
[user@home]>

对于严肃的工作,使用文件。

票数 2
EN

Stack Overflow用户

发布于 2022-03-29 19:26:21

定义

库或应用程序称为system.

  • packages是命名空间,symbols

  • symbols是命名对象,通常驻留在包

中。

:BAR表示包FOO中名为BAR的符号。

FOO:BAR表示包FOO中导出的名为BAR的符号。

栏表示当前包中的符号条。

若要读取带有特定包的符号,则该包需要存在

示例:

在LispWorks中有一个名为CAPI ->的包,我们可以找到它。

代码语言:javascript
复制
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的包裹。我们找不到它:

代码语言:javascript
复制
CL-USER 46 > (find-package "FOO")
NIL

现在读取包FOO中的符号是一个错误,因为包不存在:

代码语言:javascript
复制
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

代码语言:javascript
复制
(progn
  (ql:quickload "cl-ppcre")
  (funcall (find-symbol "SPLIT" "CL-PPCRE") "\\s+" "1 2 3"))

上面避免提到符号cl-ppcre:split。相反,我们通过find-symbol在运行时查找它。

或者:

代码语言:javascript
复制
(progn
   (ql:quickload "cl-ppcre")
   (eval (read-from-string "(cl-ppcre:split  \"\\\\s+\" \"1 2 3\")")))

或者:把它变成两种形式:

代码语言:javascript
复制
  (ql:quickload "cl-ppcre")  ; loading the software
                             ;  also creates the package CL-PPCRE
  (cl-ppcre:split "CL-PPCRE") "\\s+" "1 2 3"))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71657797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档