如何远程操作 REPL

之前在知乎上回答了一个问题:《如何可以让全世界 lisper 在同一个REPL的不同终端下一起工作?》

以下为我的原回答:

楼主说的应该是让 Lisp 的 REPL 支持远程连接吧?

Slime 环境下比较简单,就是让后端的 Swank 监听个端口,再映射出来就可以了,官方文档中有述:SLIME User Manual, version 2.11: Connecting to a remote lisp

之所以可以这样工作,是因为 Common Lisp 本身工作机制,它运行在 REPL 环境下,这样能动态修改内存中的数据,这样就可以实现热补丁了。

我用 Common Lisp 做 Web 开发时,会在才上线程序后开启一个远程的 REPL 一段时间,这样如果遇到 bug,我就可以本地给运行在远程的 Lisp 程序动态打热补丁,而不用一系列的流程:打包、上传,甚至先中断服务,再部署新代码。当然这种开发模式更加适合个人开发,而不是团队开发。

另外相传 NASA 的飞船在太空呆了半年后,发现代码中的一个 bug 会导致系统出错,他们就连接到远程的 REPL 给 Lisp 代码打的热补丁。

实践起来其实只需几个简单的步骤:

1、在远程服务器中的 Common Lisp 镜像中加载 Swank,可直接用 Quicklisp:

(ql:quickload "swank")

2、启动 Swank 服务,默认监听端口为 4005,指定 :PORT 参数可以修改端口号:

(swank:create-server)

3、在本地使用 SSH 做端口转发,将远程的 4005 端口转发到本地的 4005 端口上:

ssh -L4005:127.0.0.1:4005 shellcodes.org

4、本地启动 Emacs 并执行:

M-x slime-connect 回车 回车

这时在本地的 Slime 中启动的镜像实质上对应的是远程服务器上运行的 Lisp 镜像,在 REPL 中做的任何操作都是在远程生效的。

简单来说,Common Lisp 代码运行在镜像(Image)之中,好比进程运行在操作系统之上。而 Swank 则是 Emacs 和 Lisp 镜像之间的通讯协议,上面的操作步骤只是做了一个端口转发而已。

这种方式对那种不能中断的服务打热补丁、修改功能、增加新功能等等来说是极其有用的。

有关 Swank 协议,详细可参考:https://github.com/astine/swank-client/blob/master/swank-description.markdown