17

我是一名初级程序员,正在阅读《Land of Lisp》一书。

我一直在用 REPL 输入书中的示例。是否可以将我当前的程序保存为 .lisp 文件,以便我可以加载它并在以后继续处理它?我知道我可以在文本编辑器中创建 .lisp 文件并加载它们,但我很喜欢在全屏模式下使用 REPL 来执行示例。

4

2 回答 2

21

简短的回答

不,一旦你在 REPL 中输入了一个函数,源代码就消失了,你只剩下解释或编译的形式。你可以做一些聪明的事情,但我怀疑你现在不想处理它们。

长答案

使用 Emacs 和 SLIME

首先,我知道您喜欢 REPL,但我鼓励您查看一些支持 Lisp 的编辑器,例如带有 SLIME 的 Emacs ( http://common-lisp.net/project/slime/ ),它为您提供两全其美的。你在编辑器中输入,它在 REPL 中输入,你真的不知道你现在做事的方式有什么不同。然后您可以将您喜欢的函数复制并粘贴到“正确的”.lisp 文件中。使用 Emacs 的另一个优点是它基于 Lisp 的一种变体,称为 Elisp,因此您可以在 Lisp 中编写您的编辑器。您可以漂亮地打印您的代码,重新格式化并将其重构为多个函数,并做各种出色的事情。

讲道够了!

如果您仍然只想键入 clisp 并在 REPL 上玩,那么您仍然可以选择。

如果要记录 REPL 会话的输出,请查看 DRIBBLE。它会将您的会话记录到一个文件中,您可以稍后对其进行编辑以提取您想要的内容。

例如,这是一个简单的会话:

ataylor:~  $ clisp

胡说八道

[1]> (dribble "/Users/ataylor/jerome.lisp")
#<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"/Users/ataylor/jerome.lisp">
[2]> (defun add-two (a b) (+ a b))
ADD-TWO
[3]> (add-two 1 2)
3
[4]> (dribble)
#<CLOSED OUTPUT BUFFERED FILE-STREAM CHARACTER #P"/Users/ataylor/jerome.lisp">
[5]> 
Bye.

查看文件的内容很容易,但它会很快变大。

ataylor:~  $ cat jerome.lisp 
;; Dribble of #<IO TERMINAL-STREAM> started on 2011-09-14 18:16:57.
#<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"/Users/ataylor/jerome.lisp">
[2]> (defun add-two (a b) (+ a b))
ADD-TWO
[3]> (add-two 1 2)
3
[4]> (dribble)
;; Dribble of #<IO TERMINAL-STREAM> finished on 2011-09-14 18:17:16.

您可以将其复制(defun add-two (a b) (+ a b))并粘贴到文件中以供以后使用。

加载该文件(我将其添加到jerome1.lisp)非常简单。

ataylor:~  $ cat jerome1.lisp 
(defun add-two (a b) (+ a b))
ataylor:~  $ clisp

胡说八道

[1]> (load "/Users/ataylor/jerome1.lisp")
;; Loading file /Users/ataylor/jerome1.lisp ...
;; Loaded file /Users/ataylor/jerome1.lisp
T
[2]> (add-two 1 2)
3
[3]> 
Bye.

保存会话

您可以做的最简单的事情是将 Lisp 会话保存到图像中。它将保存您创建或编译的所有函数以及大多数状态。当您在下一次会话中加载它时,几乎就像您没有退出 clisp。执行此操作的方法取决于实现,并且在 clisp、sbcl 等之间有所不同。我将向您展示您将为 clisp 做什么。

这样做的问题是您无法打开文件并对其进行编辑,将其发布到 github 或其他任何地方。我将举一个简单的例子。

ataylor:~  $ clisp

胡说八道

[1]> (defun add-two (a b) (+ a b))
ADD-TWO
[2]> (add-two 1 2)
3
[3]> (EXT:SAVEINITMEM)
;; Wrote the memory image into lispinit.mem (3,422,616 bytes)
Bytes permanently allocated:            171,840
Bytes currently in use:               3,243,400
Bytes available until next GC:          808,130
3243400 ;
808130 ;
171840 ;
1 ;
65640 ;
7834
[4]> 
Bye.

请注意有关 clisp 写入内存映像的位置的消息。-M下次启动时,您将使用标志将其返回给 clisp 。

ataylor:~  $ clisp -M lispinit.mem 

胡说八道

[1]> (add-two 1 2)
3
于 2011-09-15T01:49:45.420 回答
1

由于以下原因,我想要更好地回答同样的问题:

(1) 在学习一门语言时,您通常更想进行实验而不是实际编写完整的应用程序。

(2) 进行实验时,查看您的历史记录并查看您输入的内容和获得的结果会非常好。

(3) 我来自 世界bash,在那里您可以将命令历史记录直接转储到文本文件中,并将其称为“脚本”(尽管这只是实际bash脚本功能的一小部分,但它仍然可以使用事后自动化的目的,稍微清理一下。)

因此,从 . 世界开始bash,我只是选择了简单的路线——我自动清理了 stdout 转储。如果您正在使用带有回滚历史的终端(除了虚拟终端之外的任何东西 - 如果您在 VT 中编写 lisp 代码,您就很奇怪)以clisp交互方式玩,只需将整个终端回滚历史复制到文件中,然后运行:

sed -n -e 's/^\[[0-9]\+\]> //;tstuff' -e 'b;:stuff' -e 'p;:rep' -e 's/([^()]*)//;trep' -e '/^[^(]*$/{s/.*//;h;d;};h;n;p;x;G;brep' myfile.lisphist > myfile.lisp

魔法!你有一个工作的 lisp 程序。(显然你应该清理它;目的是拥有你的历史,而不是真正将它用作程序。但它只会包含你输入的 lisp 命令,而不是输出/结果,所以它可以直接用作程序文件。)

然后你就可以跑了clisp -repl myfile.lisp,瞧!你又回到了上次会话的地方。当然,要交互式加载它,您应该取出最后(quit)一行。:)

至于该sed命令,它所做的是查找clispprompt [number]>,然后打印该行(删除提示),然后尝试平衡括号。如果成功,则扫描下一个提示;如果括号不平衡,它会打印行直到它们平衡。

实际上,它可以稍微简化为:

sed -n -e '/^\[[0-9]\+\]> /{s///;p;:rep' -e 's/([^()]*)//;trep' -e '/^[^(]*$/d;h;n;p;x;G;brep' -e '}' myfile.lisphist > myfile.lisp

(注意:我不使用emacs;我一直在使用clisp直接在命令行中调用。我不知道 SLIME 中是否有回滚历史。

于 2015-12-15T07:36:15.493 回答