Can I save source files in Clisp?

18

我是一名初学者程序员,正在学习《Lisp之国》这本书。

我已经在REPL中输入了这本书的例子。现在,我想知道是否可以将当前的程序保存为.lisp文件,以便稍后加载并继续工作?我知道我可以在文本编辑器中创建.lisp文件并加载它们,但我喜欢使用全屏模式下的REPL来完成这些例子。


我在想是否可以将一个进程作为其标准输入管道到clisp,并记录它读取的标准输入并将其回显。然后理论上,为了重新加载它,只需让初始管道程序在开始读取真正的标准输入之前打印出该日志即可... 这有点像黑客行为,不确定是否可行,但从理论上讲... - bambams
2个回答

22

简短回答

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

详细回答

使用Emacs和SLIME

首先,我知道您喜欢REPL,但我建议您查看一些带有Lisp支持的编辑器,例如带有SLIME的Emacs(http://common-lisp.net/project/slime/),它为您提供了最佳选择。您在编辑器中键入,它会在REPL中键入,您真的不知道与您现在所做的有什么区别。然后,您可以将喜欢的函数复制并粘贴到“适当”的.lisp文件中。使用Emacs的另一个优点是它基于一种称为Elisp的Lisp变体,因此您可以用Lisp编程您的编辑器。您可以对代码进行漂亮的打印,重新格式化和重构成多个函数,并执行各种出色的操作。

够了吧!

如果您仍然只想键入clisp并在REPL中玩耍,那么您仍然有选择。

如果要记录REPL会话的输出,请查看DRIBBLE。它将将您的会话记录到文件中,您可以稍后编辑该文件以提取所需内容。

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

ataylor:~  $ clisp

blah blah

[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

blah blah

[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

blah blah

[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 

blah blah

[1]> (add-two 1 2)
3

1
没问题!我喜欢在任何时候都鼓励Lisp程序员。 :-) - Art Taylor

1
我希望能得到一个更好的答案来解决以下问题:
(1)在学习一门语言时,往往更想进行实验而不是编写完整的应用程序。
(2)在进行实验时,查看历史记录并了解输入和结果非常有帮助。
(3)我来自于的世界,你可以将命令历史记录直接转储到文本文件中,并称之为“脚本”(尽管这只是实际脚本的一小部分功能,但它仍然可以实现事后自动化处理,稍加清理即可)。
因此,从的世界出发,我选择了简单的方法——自动清理stdout dump。如果你正在使用具有回滚历史记录的终端(除了虚拟终端以外的任何终端,如果你在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提示符[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中是否有回滚历史记录。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接