我成为 Lisp 程序员的道路曲折而漫长。我曾于 2007 年 10 月 3 日在本身的日记中总结了本身的学习经历,现抄录于此。最先在 2000 年 5 月,斯托曼院士访华时告诉我,Lisp (或者它的现代变种 Scheme)是功能最强大的编程语言,他本人就是一位高级的 Lisp 程序员,他还精通 C,GNU Emacs 就是采用 C 和 Lisp 二者开发的。我当时已经掌握了 C,但不会用 Lisp,可是我彻底相信他说的都是真的。因而,一心想成为编程高手的我,决定学习和掌握这门编程语言。我从 2000 年下半年开始学习 Lisp。下面总结的学习经历大体按照时间前后顺序排出:有必要先说明一点,在我遇到斯托曼院士以前,我在上大学时曾经阅读过一本关于人工智能的著做,《Artificial Intelligence --- Making machines "think"》,做者是 Neill Graham,这本书的最后一章(第14章)是关于 Lisp 语言的简介,因此我对人工智能和 Lisp 的概念并不彻底陌生。这本书前面的章节都很好理解,可是在这最后一章,我遇到了很大困难。我花了许多时间试图明白其中的道理,不过最 后成效不彰,如今回想起来,究其缘故,最主要的就是我没有一个适当的上机练习环境,在读了许多书中的东西后,当时我感受彷佛明白了其 道理,可是实际上并无真正理解清楚。不过,有两点在我看来无疑是肯定的:1、Lisp 早已经成为人工智能研究项目的首选(或者说是默认的)编程工具,在人工智能领域没有其余语言能撼动其领导地位。2、对于具备表结构的 数据操做,对于列表(list)头元素(pair 的 car 的部分)的处理采用递归方式比较好,而对于众多的体元素(pair 的 cdr 的部分)则采用迭代的方式处理效率更好。斯托曼院士回国后,我首先在计算机上尝试用 Emacs Lisp 编程,它是嵌入在 GNU Emacs 文本编辑器中的解释器。在庞大的 Lisp 家谱中,Emacs Lisp 不是 Common Lisp,而是早期的 MacLisp 的一个直系后代,同时在一些方面做了简化和强化。同时我开始阅读 Robert Chassell 所著 《Introduction to Emacs Lisp Programming》,Robert Chassell 是斯托曼院士早年结识的战友,也是自由软件基金会的合创人之一, 他很早就使用 GNU Emacs,并且使用 Emacs Lisp 程序定制 GNU Emacs,斯托曼友善地把 Robert Chassell 介绍给我认识。 这本书既是自由文档(能够从 GNU 的网站自由下载),又是自由软件基金会出版社(GNU Press)的出版物。等我读完了这本书以后,我以为这本书实在太美妙了,做者的文笔十分了不得(即便对于想学习英文写做的人,帮助 也应该很大),把这本书介绍给其余人是彻底值得的。我因而找了两位翻译人员(毛文涛博士和吕芳女士),把它译成了中文,我则担任了全 书的编辑和审校工做。中文版质量很高,我很满意,它做为一本很伟大的编程入门书籍十分适合广大读者自学(我认为读者应该搞到一本阅 读)。我至今还想本身动手翻译这本书的第三版,惋惜现在我很难再找到当年那么多的时间作编辑和审校之类的工做了。阅读完这本书以后,我意识到若是想使用 Emacs Lisp 开发非玩具级别的实际应用程序,那么根据做者的推荐,自由软件基金会出版的 《GNU Emacs Lisp Reference Manual》是必不可少的工具书,我打印了这份文档的第 2.4 版本,厚厚的共四本。后来这份文档正式出版,从 GNU 网站上订购的图书升级到了 2.6 版本,针对的是 GNU Emacs version 21。我不太认同 Eric Raymond 在他的名著 《The Art of Unix Programming》中对 Emacs Lisp 的评论,他觉得 Emacs Lisp 只能为 Emacs 编辑器自己编写控制程序,而赶不上其余脚本语言全面。实际上,我认为只要熟悉了 Emacs Lisp 的细节,其余任何脚本语言能完成的工做,均可以使用 Emacs Lisp 程序完成。我亲眼看见斯托曼院士在 GNU Emacs 内完成电子邮件的编辑、收发等工做,不用 Eric Raymond 开发的 fetchmail 程序同样干得很好。我本身也利用 Emacs Lisp 编写过 CGI 应用程序,效果也不错。Bob Glickstein 曾经写过一本《Writing GNU Emacs Extensions》,能够配合 Robert Chassell 的书与《GNU Emacs Lisp Reference Manual》,做为补充读物。读了 Robert Chassell 的书以后,我开始花时间阅读 David Touretzky 博士所著的 《Common Lisp: A Gentle Introduction to Symbolic Computation》,这本书能够从互联网上自由下载,读者能够自行在 万维网上 google 获得它。 这也是一本伟大的 Lisp 著做,内容已是基于 Common Lisp 的,可是做者并无特地强调这一点。我把下载的 PDF 文件打印出来,本身动手把打印出的文档纸张装订成了两卷手册。 我从这本书中获得的最大收获是我充分认识到 Lisp 中的一切都是对象:数字原子(numeric atoms)和符号原子(symbolic atoms)都是对象。数字原子求值返回它自身的值,而符号原子则有名称(name)、类型(type)、值(value)、秉性表 (plist)和绑定表(bindlist)。这五个字段能够放入一个数据结构中,并在实现中以 C 语言的 struct 表达。在阅读这些材料的同时,我又从网上找到了 Gary Knott 教授编写的一份文档,《Interpreting Lisp》,这份文档篇幅不长,历来没有正式出版成书。在这份文档中,做者利用 C 语言编写了一个微小的 Lisp 实现,很是接近于最初的 Lisp 实现。最难得的是他将实现的源代码和盘托出。从这本书中, 我清晰地看到了如何构造 Lisp 对象的结构,我开始认识到内存垃圾收集算法的重要性。在理解了 David Touretzky 博士所著的 《Common Lisp: A Gentle Introduction to Symbolic Computation》介绍的 Lisp 对象的结构基础上,我明白了书中图示的 Lisp 对象中若仅在结构设计时安排五个字段是不够的,还须要有供垃圾回收(GC,Garbage CCollector)模块操做的字段才行。在 2001-2002 期间,我开始接触 Scheme。在此以前的 2000 年 8 月,Rorbert Chassell 曾来中国访问,咱们在西安时,他向我介绍了 Scheme 是我应该关注的语言。Scheme 于 1985 年诞生于 MIT,发明人有两位:一位是 Gerald Sussman 教授,他是自由软件基金会的董事会成员之一,另外一位是 Guy J.Steele 博士,下面即将更多地提到。我首先使用了 Dorai Sitaram 所著的教材《Teaching Yourself Scheme in Fixnum Days》,这份文档能够从网络自由下载,不过坦率地说,这本书教材不太适合初学者,阅读它的人至少应该具备不少基础知识或者经验才 行。我并无从这本书从得到太多的帮助,对 Scheme 的基本概念也没有搞清楚,特别是连续(Continuation)之类的概念没有理解。不过,收获仍是有不少,我意识到 Scheme 是一个很是优美的 Lisp 变种,它继承了源自 Algol60 和早期 Lisp 二者的特色。这份教材的最后还列举出了一个具体的编程实例,讲授如何利用 Scheme 编写 CGI 程序。如今我看来,在 CGI 编程等领域, Perl 和 PHP 等脚本语言得到普遍应用简直就是钻了 Lisp 社团不善营销的空子。到了 2001 夏天,我从美国得到了《Structure and Interpretation of Computer Programs》的教师手册,是个人朋友 James Gray 帮我买的,他是我一个很好的朋友,不过我这里要善意地埋怨一下,他作事有些马大哈,我原来但愿他给我搞到这本书的学生用书,没有想到 他却寄来了教师手册,我想他在买书时没有仔细区分一下,而此著做的教师手册和学生用书的封面都采用了同一图案,做者和 MIT 出版社的编辑的确很优秀,他们在营销本书时很是成功,后来专门还开设了一个网站推广本书和相关的教学材料,网上公布了教材的所有内 容,加上两位做者课堂教学的视频录像。 教师手册价格比较便宜,James 在购买时要么没有仔细辨认清楚,要么就是帮我省钱,才寄来了这本教师手册。我当时没有学生手册,也就没有继续学习 Scheme。不过话说回来,James 寄给个人教师手册我一直都留在我手头,后来对于我在黑客道教学中讲授 Scheme 帮助极大,在这里仍是应该深深地感谢 James Gray。不久(2003年),我买了一本 Patrick Winston 教授所著的《Common Lisp》第三版, 做者是麻省理工学院人工智能实验室的主任(斯托曼早年就是他手下的兵),在美国的人工智能研究领域名气很大,我就是冲着他的名气才买 此书的。阅读完以后,我以为这位教授名副其实,而不像我在国内见到的一些人徒有虚名,拿不出真东西。 这是一本介绍 Common Lisp 的极好教材。后来 Hans Hagen (ConTeXt 排版软件包的主要做者之一)告诉我这本书的合著者 Berthold Klaus Paul Horn 在 TeX 社团名气也很大,的确如此,从本书的排版质量便可看出许多名堂来,排版样式一看就是典型的 TeX 风格。 做为中文 TeX 用户俱乐部(CTUG)的主席,我已经知道,国内学术界(我指的是数学界和计算机科学技术界)不多有人精通 TeX 排版系统,鲜有人能使用它排版本身的讲义或著做。读了这本书以后,我感受本身必须阅读 Common Lisp 的语言参考手册,许多问题必须在看到语言规范(这是基本的尺度)以后才能搞清楚。 Guy L. Steele 博士写过这样的手册,并且他写了两次,第一个版本是在 Common Lisp 标准化以前完成的,第二个版本是在标准化完成以后写成的,可是网上有人评论说有些该写的东西没有写进去,此书是否会有第三版不得而 知。Guy L. Steele 博士是很是著名的语言手册的做者,他已经为 C、Common Lisp、Java 等编程语言都写过的语言参考手册,都很是成功,这些参考手册都是一版再版,销路极好,比位于瑞士的国家标准化组织(ISO)发布的非 常昂贵的标准文档销路好许多。他写的这些语言参考手册已经成为编写这些语言编译器做者们的大救星。大约在同时,我下载了 《On Lisp》,这是 Paul Graham 博士编写的一本优秀著做,从中我获得了许多 Lisp 概念的细节,特别是 Lisp 的 macro 机制,以及黑客们如何利用 Lisp 思考问题。做者介绍的自底向上(bottom up)的方法论对我触动很大,而做者的讲解是很是富于启发性的(做者曾专程赴意大利的美术学院学习过油画创做,因此具备很高的艺术修 养)。从那时开始,混合编程(Hybrid Programming)的思想在我头脑中开始成型,我坚信 Lisp 将会成为一种很是长寿的编程语言,这使我联想起斯托曼院士当年在四川九寨沟就 GNU Emacs 开发对我讲过的话。在 GNU Emacs 和 Lisp 背后隐含的方法论是永远不会过期的。2004 年,我真正找到了 Lisp 编程的感受,以为本身开始进入状态,并开始使用 Scheme 开发真正的应用程序,我编写的程序是一个网络应用程序,即一个网络留言板(Web-based bulletin System),在万维网上能够运行,CGI 的模块是采用 Scheme 写的,Apache 在服务器上经过 Scheme 的 CGI 程序接上了 PostgreSQL 数据库。我使用的是 PLT Scheme 的 103 版本,我很是喜欢这个版本,既简单又很干净,我用 C 语言和 PostgreSQL 提供的 libpg 编写了一个 DA (database adaptor),让 Scheme 程序能够访问 PostgreSQL 数据库。完成了这个项目以后,好事成双,我获得了渴望已久的《Structure and Interpretation of Computer Programs》(简称 SICP,或者“紫皮书”),做者就是 Harold Abelson 教授和 Gerald Sussman 教授。正是这一年,我开始利用本身头脑中造成的数学观点,特别是在个人泛系尺度论中表达的思想,来认真学习 Scheme,而且主动地从中国古代的阴阳太极图模型来理解当今电子计算机系统上的计算模型。这一过程延续了很长时间,直到 2005 年的冬天才最终得到成功! 这期间的许多思想写入了个人著做《自由软件:新的游戏规则》第三卷内篇的第二章“论尺度”。从此我还准备花更多的时间把它扩展开来, 造成一部单行本的著做《泛系尺度论》,在这个单行本中,我将利用更长的篇幅把中国古代的哲理思想、现代数学思想和计算机编程融为一 体,对整个计算理论提出本身完整的一家之言。在黑客道九个段位中,初段就是讲“计算的本质”,里面就归入了个人思想方法和编程经验。2004-2005 年期间,我仔细地研究了 R5RS 文档中除了第七章以外的全部内容,收获巨大。对于第七章的内容,当时仍然有些疑惑,由于这些材料须要理解大量的关于 lambda calculi 的细节和大量的预备知识,我当时尚未找到充分的材料钻研。另外,在研究 PLT Scheme 的源代码时,内存垃圾回收算法对我而言,仍然是一大疑难问题,显然,对于内存垃圾回收技术,我还须要学习更多的背景材料。到了 2005 年的年末,我把 R5RS 翻译成了中文。在完成翻译的过程当中,我知道了如何利用形式语言和扩展的巴科斯-劳尔范式(EBNF)来定义一门编程语言的形式句法和 语义规则,以及如何正确理解和读懂它。2005-2006期间,我学习了其余许多关于 Lisp 编程的书籍,包括 Paul Graham 博士的《ANSI Common Lisp》、 Matthew Flatt 等人合著的 《How to Design Programs》, Brian Harvey 和 Matthew Wright 合著的 《Simply Scheme --- Introducing Computer Science》(此书的封面设计别出心裁,很是值得回味)、Daniel Friedmann 和 Matthias Felleisen 合著的 《The Little Schemer》 和《The Seasoned Schemer》。另外我花了至关多的时间仔细阅读 《The Scheme Programming Language, 3e》,这是 R. Dybvig 教授的表明做,他是 Chez Scheme 实现的设计大师。年末我获得了 《Hackers and Painters》(“黑客和画家”),这是 Paul Graham 博士所著的散文集,与 Robert Chassell 同样,他也是一位伟大的做家,他的行文很是容易阅读,并且这本书中的内容如同其书名副标题同样,的确收入了许多伟大的想法,这些想法 对于创新公司利用 Lisp 开发创新项目是很是富有启发性的。2006 年 7 月 15 日,个人学生千俊哲从南韩的汉城大学带来了他学习的两本著做的复印件:George Springer 和 Daniel P. Friedman 合著的《Scheme and the Art of Programming》,以及 Mark Watson 的 《Programming in Scheme: Learn Scheme through Artificial Intelligence Programs》。前一本的难度在紫皮书之下,比较好读,其中许多程序如同棋谱同样,展示了许多高级编程技巧,值得反复思考,我立 即在 PLT Scheme 实现上验证了书中的大部分代码;后一本则介绍如何使用 MIT Scheme 来设计人工智能程序,很是精彩。2006 年 7 月送走了千俊哲以后的夏天,我一直在瑞士苏黎世度假(八月下旬我还去了西班牙马德里参加了国际数学家大会),苏黎世中央图书馆 (ZB,Zentralbibliothek Zuerich)是一所了不得的图书馆,现有藏书一百二十万种。听说列宁当年在欧洲流亡时曾来到苏黎世,就睡在这个图书馆里读书学 习。八月份时,大多数瑞士人也在休假,图书馆的人很少,很是安静。我在这段时间从图书馆中找到了很是多的背景材料, 包括 H.P. Barendregt 所著的数学经典教材 《The Lambda Calculus --- Its Syntax and Semantics》,这本书于 1981 年由 North Holland 出版社出版,对这一数学分支做了详尽的介绍,我认为对于这一主题, 从此再也无人能够写得比这本著做更好了。 另外,我找到了第一本关于 lambda calculus 的著做,是由这个理论的创始人 Alonzo Church 教授创做的,《The Calculi of Lambda-conversion》 简直是无价之宝,在这本小册子中,做为数学家,做者清晰而精炼地阐明了 lambda calculi 的所有内容。任何一位想掌握 lambda calculus 的人都应该仔细阅读本书。在图书馆中还找到了 《An Introduction to Lmabda Calculi for Computer Scientists》, 做者是 Chris Hankin。 Matthias Felleisen 和 Matthew Flatt 合写的 《Programming Language and Lambda Calculi》也打印出来了,并仔细阅读了两遍,这两人是 PLT Scheme 研发小组的核心成员。 在苏黎世中央图书馆的书架上,我还看到了 SCIP 紫皮书的初版的德文本,书中的内容与英文版第二版大同小异,可是我敏锐地发现,初版的第四章中没有收入 eval 和 apply 两个高阶算子构成的太极推手图,第二版中则出现了。我花时间研究了 《Lisp 1.5 Programmer's Manual》,这是世界上第一份真正意义上正式发布过的 Lisp 稳定实现版本的手册,做者就是 John McCarthy 等人,极具学术权威性,我认为任何一位 Lisp 程序员都应该阅读这本手册。时隔多年后,我又开始阅读关于人工智能方面的著做,《Lisp, Lore and Logic》是 W. Richard Stark 写的,《Artificial Intelligence, theory and practice》 是 Thomas Dean 等人写的,他们都已经使用 Common Lisp 来讲明问题。阅读时,我参考了前面已经提到的 Partrick Winston 教授编写的经典教材 《Artificial Intelligence, 3e》。2007 年初,我开始关注 Scheme 社团中尚处于起草状态中的 R6RS,这个文件将成为新的 Scheme 语言规范。我如今仍然认为 Common Lisp 太复杂、太庞大,回厂大修彷佛也不太可能,由于工业界已经很好地接受了 Common Lisp,而 Scheme 将是将来的主流。我开始按照这一规范来开发本身的 Scheme 实现版本,这一实现版本称为 MNM Scheme。2007年6月至7月间,我在瑞士苏黎世的 Campus Zollikerberg 打印了 R5.97RS,我花了许多时间理解这一新的规范,特别是它与前一个版本(R5RS)的差别。同时,我从新思考了 PLT Scheme 实现的源代码和涉及模块(modules)、名称空间(namespaces)、盒子(box)类型、define-values 和其余附加在 R5RS 规范之上的特性与实现风格。从苏黎世中央图书馆借到的另一本具备重大价值的著做就是 Richard Jones 和 Rafael Lins 合著的《Garbage Collection》,这本书极大地帮助我理解了内存垃圾回收算法设计的细节。我今后开始真正明白了 Scheme 实现工做中的最后一个阴暗角落。对于一切 Lisp 对象,内存垃圾收集的算法设计时其实不存在理论上的最优算法,算法的效率受到多种因素的影响,而 Lisp 的设计者能够根据本身的设计思想来决定应该怎样回收内存垃圾。这时的我已经成长为熟练的 C++ 程序员,站在 C++ 程序员的立场看,一切 Lisp 对象都有类型,我能够用 C++ 语言内置的类(class)来刻画它们(即声明各类用户自定义的类),一切 Lisp 对象从存储空间分配和回收的角度来看具备共性,因此,这能够利用 C++ 的模板来表达 Lisp 对象的存储管理结构,而各个 Lisp 对象占有的存储空间大小,则能够利用类的构造函数(constructor)和析构函数(destructor)对内存分配和内存垃 圾回收在模板的支持下进行统一的操做。源自 Lisp 发展起来的 GC 是一项“古老”的技术,实际上它已经普遍地被采用了,Java 这门当今新的商业编程语言中就有,并且 Java 的 GC 算法设计得很是好,我决定在个人 Scheme 实现中参考它。2007 年 9 月,我在从香港飞往苏黎世的飞机上,我阅读了美国著名的程序员 Bruce Eckel 所著的 《Thinking in Java》的第四版原著,从做者的介绍中,我结合从《Garbage Collection》中得到的知识,我理解了 Java 的内存垃圾回收算法的整体思路,并构思了如何利用他们的算法来改进个人设计。 而在我离开苏黎世回国的同一天(2007年9月26日),R6RS 技术委员会的全体编辑成员决定冻结对草案的讨论,正式发布了这一规范,从那一天起,我实现 MNM Scheme 的步伐也大大加快了。(不过,请读者留意在委员会举办的投票时,也有许多人投了反对票,并给出了反对意见,这些意见与支持的意见一 起,都是极有研究价值的。)Scheme 的实现版本很是多,并且本身可否动手实现一个是考验一个计算机专业人士学术修养深浅的好指标(这也是我在黑客道中把第五段的教学内 容 定为“解释器的原理与构造”的缘由之一)。迄今优秀的 Scheme 实现有: PLT Scheme、MIT Scheme、Chez Scheme 等等。我认为 PLT Scheme 是很是优秀的实现版本,它是按照 GPL 发布的自由软件,值得在这里推荐给广大读者。绝不客气地讲,个人 MNM Scheme 也应该算一个。Common Lisp 的实现版本不少,抛开 Franz Lisp 等商业版本不谈,自由软件社团中最有名的两个实现分别是:Bruno Haible 等人从 1992 年以来一直维护和开发的 CLISP,以及卡耐基梅隆大学的小组开发 CMU Common Lisp。这两个 Common Lisp 实现都很好,我我的比较喜欢使用 CLISP。目前最好的 Common Lisp 编程著做可推荐 Peter Seibel 写的 《Practical Common Lisp》,这位做者的天分显然比我高,他原来是 Java 和 Perl 程序员,2004年才开始学习 Common Lisp,他花了一年的时间学习它,就彻底学会了,并且在学习的同时,边练习、边写书,结果很丰硕,写出的这本书就是读者能看到的结 果,这本书获得了普遍的承认,它出版后得到了美国出版界计算机图书创做的震撼大奖。他在一次采访中提出了一个新的说法:时代的发展需 要“第二代 Lisp 程序员”,并且每一个程序员都应该学习 Lisp。(让我再次回忆起斯托曼院士在 2000 年时对我说过的话。)正如读者在上面所读到的,成为一位了解 Lisp 一切内幕的程序员可真不容易,可是我很高兴,由于我已经成功地逾越过了这个初看起来曾经很是高的门槛,我如今已是这样一位程序员 了。学习 Lisp 给我带来了巨大的乐趣,若是没有这种在编程中产生的乐趣相伴,我绝对不会花这么长的时间来学习它。今天,我由衷地自豪,由于若是按照 Peter Seibel 的说法和衡量标准,我已是第二代优秀的 Lisp 程序员群体中的一分子。上面罗列的学习经历对于通常人而言显然太长了,黑客道学员们则能够站在个人肩膀上,借鉴个人经验和教训,少走许多弯路、避免走死胡 同。值得庆幸的是,我已经在黑客道的课程设计中自觉地作了许多工做,凡是参加了黑客道的初段课程学习的学员(S1:“计算的本 质”),便可在较短的时间内学会掌握 Lisp。