按:本文是我在阅读Peter Seibel所著的Common Lisp教程Practical Common Lisp(免费在线阅读地址:http://gigamonkeys.com/book/)的学习笔记。这篇文章的主要内容包括Common Lisp的介绍以及如何搭建Common Lisp编程环境(SBCL + Emacs + SLIME)两部分。因为本文并不怎么涉及Common Lisp的具体知识,所以编号为0。
目录
什么是Common Lisp
在讲解一样东西前先对它进行一番介绍是个好习惯,所以本文的第一个内容便是对Common Lisp的介绍。
Common Lisp是一中编程语言,它是Lisp的诸多方言中的一种。
Lisp的原始写法似乎应该是LISP,即LISt Processor的缩写,不过Lisp这种写法似乎比LISP更常见(而且,在我看来,也更可爱 = =)。Lisp是John McCarthy在1960年左右创造的一种基于λ演算的函数式编程语言,可以说是历史悠久、源远流长(其古老程度和FORTRAN老哥有一拼)。当然在初期由于没有什么统一的规范或者标准,不同的人采用了不同的方式对Lisp进行实现,也就出现了许多方言,Common Lisp便是其中一种(另一个主要的Lisp方言是Scheme,此外还有一个和Emacs一起的Emacs Lisp)。
我是通过Peter Seibel所著的Practical Common Lisp一书(免费在线阅读地址:http://gigamonkeys.com/book/)来学习Common Lisp的。此前我有翻过Paul Graham的ANSI Common Lisp,尽管我是被后者的作者的洗脑带上学习Common Lisp的道路的,但我认为它并不适合作为Common Lisp的入门教程(尽管看起来它的定位是Common Lisp入门教程),读这本书会感觉很累,而且恐怕要很久以后才能看到Common Lisp的优势(我读这本书读了好几章都没读到)。而Peter Seibel的这本Practical Common Lisp的第三章便有一个实际的项目——实现一个非常简单的音乐数据库,在这一开始你就能对Common Lisp的各种概念(包括Paul Graham所极力称赞的macro)有一个大致的了解。
搭建Common Lisp编程环境
搭建Common Lisp编程环境的方法有很多种,这里我使用的是最常见的一种:SBCL + Emacs + SLIME。
SBCL是Steel Bank Common Lisp的简称,它是Common Lisp的一种高质量的开源实现,可以运行在Linux和OS X上。其他著名的Common Lisp的实现还包括Allegro Common Lisp(商业软件,可运行于Linux,Windows以及OS X),OpenMCL(开源软件,据说非常适合OS X用户)等。我是直接使用Fedora的yum软件安装的SBCL,命令如下:
1 |
sudo yum install sbcl |
Emacs是Editor MACroS的简称(吐槽:这是哪门子的缩写),它是Linux下最受欢迎的两个文本编辑器之一(另一个是vim)。虽然从个人喜好上来说我对vim更有爱(吐槽:Emacs在设计的时候压根没考虑过我们这种二指禅用户的用户体验!),但是因为我没有找到vim上的类似Emacs SLIME的好东西(似乎有个叫Limp的东西,但名气不大我也就没去用 = =),所以还是选择了用它来搭建我的Common Lisp编程环境。在Fedora上可以直接使用yum软件安装Emacs:
1 |
sudo yum install emacs |
SLIME是the Superior Lisp Interaction Mode for Emacs的简称,从它的名字上你就能知道它是干什么的,简单来说,使用它我们可以非常轻松地体验Common Lisp编程的REPL(Read-Eval-Print Loop)旅程。在Fedora上依然可以直接使用yum软件安装SLIME:
1 |
sudo yum install emacs-slime |
只是安装完Emacs和SLIME以后还不能进入说好的Lisp Interaction Mode,可以通过修改~/.emacs文件为其进行配置。官方的说明是这样的:
1 2 3 4 |
(setq inferior-lisp-program "/opt/sbcl/bin/sbcl") ; your Lisp system (add-to-list 'load-path "~/hacking/lisp/slime/") ; your SLIME directory (require 'slime) (slime-setup) |
有看过Lisp代码的童鞋会发现,其实上面的配置文件本身就是Lisp代码,没错,Emacs这个被称作“神之编辑器”的东西就是使用Lisp语言进行扩展的。上面的文件中的第一行和第二行里需要填写Lisp system(在我这个例子中,即SBCL)和SLIME的路径,因为yum使用的软件管理程序是rpm,所以可以通过使用下面的命令就可以查看SBCL和SLIME的安装路径:
1 2 |
rpm -ql sbcl rpm -ql emacs-slime |
根据返回的结果编辑~/.emacs文件(话说,我竟然是使用vim编辑~/.emacs……),其中Lisp system的路径填写sbcl(或者其他的Lisp实现)的二进制文件路径就好(在我的例子中就是/usr/bin/sbcl),SLIME的路径应该填写那个放着包括swank-loader.lisp等很多lisp文件的目录(在我的例子中就是/usr/share/common-lisp/source/swank/),修改后我的~/.emacs文件如下:
1 2 3 4 |
(setq inferior-lisp-program "/usr/bin/sbcl") (add-to-list 'load-path "/usr/share/common-lisp/source/swank/") (require 'slime) (slime-setup) |
然后打开Emacs,在键盘上敲击M-x(在普通PC机上即同时Alt键和x键,下同),然后输入slime即可进入传说中的Lisp Interaction Mode。
注:经过这一步骤如果出现如下问题:
1 Couldn't load "/usr/share/emacs/site-lisp/slime/swank-loader.lisp"可以参考这里的解决方案(建议采用这种方法),或者在~/.emacs文件尾部添加如下代码:
123 (custom-set-variables'(slime-backend "/usr/share/common-lisp/source/swank/swank-loader.lisp"))(custom-set-faces)
进入SLIME后即可直接在里面输入Lisp代码,敲击回车键后代码会立刻被执行并输出结果,然后等待你输入下一段代码(知道为什么叫Read-Eval-Print Loop了吗?)。例如Hello World的程序代码:
1 |
(format t "Hello World!") |
得到结果如下:
1 2 |
Hello World! NIL |
其中第一行是因为执行format函数而输出到屏幕上的文字,第二行则是format函数的返回值。有过Ruby编程经验的朋友一定会对此感到十分亲切。
还可以通过输入C-x(在普通PC机上即同时Ctrl键和x键,下同),C-f,然后输入文件名来打开(如果存在)或者新建(如果不存在)一个文件。譬如我们可以新建一个hello.lisp,然后输入如下代码:
1 2 |
(defun hello-world () (format t "Hello World!")) |
然后在Emacs中移动光标到这两行中的任一行,输入C-c,C-c,即可编译这段代码到SLIME中,然后输入C-x,b,回车(其实是切换到了上一次打开的缓冲区)后进入SLIME,输入:
1 |
(hello-world) |
会发现得到了和上次一样的输出,说明我们成功编译了一个名叫hello-world的函数并成功调用了它。再输入C-x,b,回车返回hello.lisp文件,可以通过C-x,C-s保存它。通过这种方式,我们很轻松地编写、编译、运行并保存了一个lisp文件。
下面附上一些在Common Lisp编程中可能会比较常用的Emacs和SLIME快捷键(只列出一些我认为比较常用的,当然也欢迎补充):
文件操作缓冲区操作编辑操作其他操作SLIME操作
C-x,C-f | 打开或新建一个文件 |
C-x,C-v | 打开或新建一个文件,取代当前缓冲区 |
C-x,C-s | 保存当前缓冲区 |
C-x,C-w | 把当前缓冲区另存为 |
C-x,C-b | 打开缓冲区列表 |
C-x,b | 切换缓冲区 |
C-a | 移动光标到行首 |
C-e | 移动光标到行尾 |
C-v | 向下翻页 |
M-v | 向上翻页 |
C-k | 删除当前光标到此行行尾的所有字符(可以先使用C-a移动到行首以删除整行) |
C-_ | 撤销上一步操作(注意因为_是下划线,可能需要同时按住Shift键) |
Esc,数字,某操作 | 执行n遍某操作,譬如Esc,5,C-k可以删除5行 |
C-c,C-c | 编译并装载光标所在的整个Lisp Form |
C-c,C-k | 编译并装载当前缓冲区中的整个源文件 |