我是一名初级程序员,正在阅读《Land of Lisp》一书。
我一直在用 REPL 输入书中的示例。是否可以将我当前的程序保存为 .lisp 文件,以便我可以加载它并在以后继续处理它?我知道我可以在文本编辑器中创建 .lisp 文件并加载它们,但我很喜欢在全屏模式下使用 REPL 来执行示例。
我是一名初级程序员,正在阅读《Land of Lisp》一书。
我一直在用 REPL 输入书中的示例。是否可以将我当前的程序保存为 .lisp 文件,以便我可以加载它并在以后继续处理它?我知道我可以在文本编辑器中创建 .lisp 文件并加载它们,但我很喜欢在全屏模式下使用 REPL 来执行示例。
不,一旦你在 REPL 中输入了一个函数,源代码就消失了,你只剩下解释或编译的形式。你可以做一些聪明的事情,但我怀疑你现在不想处理它们。
首先,我知道您喜欢 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
由于以下原因,我想要更好地回答同样的问题:
(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
命令,它所做的是查找clisp
prompt [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 中是否有回滚历史。