在 Linux (Ubuntu WSL) 上通过 CLISP 运行 LISP 代码

问题描述

我是 LISP 的新手,想知道如何在 Ubuntu Linux 上正确运行一个简单的 lisp 程序。目前,我有一个名为“intmax.lisp”的 LISP 文件,其中包含以下代码

(defun intmax (x y) (if (> x y) x y))

但是,当我转到命令行并运行时:

clisp intmax 2 4

为了比较 2 和 4,我没有得到任何输出。关于我做错了什么的任何建议?

解决方法

要开始,请使用 REPL。那不是 shell 命令行,而是类似于 Lisp 内部的命令行。

启动 Lisp 系统:

clisp

您会收到如下提示:

[1]>

加载您的文件:

[1]> (load "intmax.lisp")

现在你可以调用你的函数了:

[2]> (intmax 2 4)

它会打印:

4

并再次提示:

[3]>

您可能希望稍后了解包和系统以便组织您的代码。

如果你想从命令行调用东西,你需要告诉 clisp 加载需要的东西,然后执行一个 lisp 命令。请查看手册页。示例:

clisp -q -i intmax.lisp -x '(intmax 2 4)'
,

clisp 可执行文件不会将其参数转换为函数调用。但是,您可以制作执行此操作的 CLISP 程序。我为 Lisp 应用程序的许可后端做了这样的事情。我想要一种简单的管理命令语言来查找用户并从系统提示中向他们授予许可证和类似的东西。所以我只是写了一个 shim,它将单个命令行参数转换成 Lisp 对象,这些对象收集到一个 List 中,并将它或多或少地作为一个函数来分派。

让我们通过在名为 clisp-dispatch.lisp 的文件中编写这个程序来热身:

#!/usr/bin/env clisp
  
(print *args*)

当我们像这样运行它时,我们看到 *args* 提供了对参数的访问:

$ chmod a+x clisp-dispatch.lisp # give it exec permission
$ ./clisp-dispatch.lisp

NIL
$ ./clisp-dispatch.lisp a b c 1 2 3
("a" "b" "c" "1" "2" "3") 

非常好。现在我们想要看到的是列表(A B C 1 2 3):符号和数字的列表,而不是字符串的列表。让我们稍微修改一下代码:

#!/usr/bin/env clisp
  
(print (mapcar #'read-from-string *args*))

read-from-string 函数使用 Lisp 阅读器扫描字符串,返回其语法隐含的 Lisp 对象。如果语法看起来像一个符号,则返回一个符号;如果是数字,则返回一个数字,依此类推。例如 (read-from-string "(1 2 3")) 产生列表 (1 2 3)。有了这个,我们得到:

$ ./clisp-dispatch.lisp a b c 1 2 3

(A B C 1 2 3) 

非常好!所以剩下的就是把这个列表当作 Lisp 代码,为此我们只需将它传递给 eval 函数。让我们保留 print,但将其用于 eval 的结果:

#!/usr/bin/env clisp

(print (eval (mapcar #'read-from-string *args*)))

现在我们可以:

$ ./clisp-dispatch.lisp + 2 2

4 
$ ./clisp-dispatch.lisp list 1 2 3

(1 2 3) 
$ ./clisp-dispatch.lisp cons "'a" 3

(A . 3) 

因此,如果我们定义一个 intmax 函数,我们可以从系统提示符处调用它。

#!/usr/bin/env clisp

(defun intmax (a b)
  (max a b))

(print (eval (mapcar #'read-from-string *args*)))

$ ./clisp-dispatch.lisp intmax 3 1

3 
$ ./clisp-dispatch.lisp intmax 7 10

10 

不过,您最好从 Lisp 内部探索 Lisp,而不是像这样从命令行间接调用它。一方面,每次我们运行这个程序时,都会启动一个新的 Lisp 映像。我们无法与环境互动。对于某些类型的语法,我们还必须使用非常笨拙的引用,例如我使用 "'a"'a 传递给 Lisp 的方式。

我们所做的是以一种非常特殊的方式使用 Lisp,而 clisp 可执行文件并不直接支持这种方式:像 Lisp 对象一样解析参数,然后将结果视为函数调用。无论如何,任何想像他一样“滥用”Lisp的人都可以编写上述小程序。

还要注意我是如何定义 intmax 的,只需调用 max。重点是在 Common Lisp 中不需要定义 intmax;内置 max 函数接受一个或多个参数并返回最大值:(max 1 3 2) 产生 3。因为 (int-max x y) 只是 (max x y),所以 int-max 没有存在的理由。它只是 max 的受损同义词,它需要输入四个以上的字符,并且不超过两个参数。