田春:走在Lisp的岔路上
田春,Common Lisp 程序员,毽球运动员,跆拳道 2 级。网名“冰河”,Glority Software 资深软件工程师,前网易杭州研究院高级开发工程师和系统管理员,资深 Common Lisp 程序员。他 2003 年起开始学习 Commom Lisp,精通 Lisp 史和各种实现,2007 年起成为 LispWorks 付费用户,Common Lisp 社区的网络专家,开源项目 cl-net-snmp(SNMP 协议库)的作者,usocket 跨平台网络库的主要维护者,common-lisp.net 站点管理员,水木社区(newsmth.net)函数型编程语言(FuncProgram)版主,美国 Versata/Gensym 公司技术顾问。他曾在 2008 年翻译了 Paul Graham 的 On Lisp 一书,在 ILC 2009(国际 Lisp 会议)上发表学术论文,在《程序员》杂志上发表 Common Lisp 专题文章,并在网上撰写过大量相关的技术文章。
图灵社区:你好,田春,可能大家更熟悉的还是你的网名“冰河”,先向社区的读者介绍一下自己,好吗?
田春:大家好。首先,关于敝人的网名,其实是自小学起就在使用的笔名或昵称,只是一个名字而已。但需要解释的是,敝人跟传说中的冰河木马没有任何关系,重名纯属巧合。
我从小学五年级开始学习计算机,早年在 NOI 信息学竞赛上只有一点小成绩,初高中阶段沉迷游戏和 DOS/Windows 编程,学习成绩很一般,高考时超常发挥才有幸考入浙大一个非计算机专业。 大学期间自学了包括 Linux 和 Lisp 在内的多种计算机知识,毕业后凭借在校期间 Linux 方面的声望进入网易公司从事系统管理,工作期间继续学习 Common Lisp,在该领域写过开源项目、发表过国际会议论文、翻译过经典英文教材,最后因机缘巧合接触到国外的古老商业 Lisp 软件,经过两年多的努力,目前以维护该软件为生。
图灵社区:你的经历真是跟 Lisp 是息息相关啊,但很多人对 Lisp 只有一个模糊的概念:这是一种中古语言,能否结合你自己的经历谈谈 Lisp?
田春:在我计算机生涯的前十年,其实完全没有想过将来会以此谋生。我选择计算机领域的具体学习方向几乎完全 是兴趣导向的。早期的时候,信息相对封闭,我和当时其他同行一样走的是从 DOS 到 Windows,从 BASIC 到C或 Pascal 再到 Visual Studio 系列,这样一个循规蹈矩的学习路线。后来到杭州读大学,不久就开始学习 Linux 和 Lisp。
我的 Lisp 经历可以分为N个阶段:
1) 人工智能编程语言阶段——小学五年级和六年级。那时有一本书,叫做《计算机应用指南》,里面讲述了 1994 年时整个计算机领域的状况,其中“人工智能与专家系统”那章里着重强调了 Lisp 和 Prolog 这两种 AI 语言的应用。这是我最早的 Lisp 印象。
2) GNU 和 Emacs 阶段——大学第一年。GNU 工程的创始人R. Stallman 早独立完成了两大自由软件:GCC 和 Emacs,后者使用一种 Emacs Lisp 语言来扩展 Emacs 环境。Stallman 本身也是 Lisp 黑客,在 Lisp 机上写过真正的 Lisp 程序,还参与过 Common Lisp 语言第一版(CLTL1)的标准制订工作。按理说所有学习 Linux 的人都多少会受到一些 Lisp 方面的熏陶,遗憾的是,最终多数人只是停留在 Emacs 和 elisp 层面上,我算是少数顺着这条 Lisp 道路一直走向终极(Common Lisp)的那些人。
3) Scheme 阶段——大学的第三年。通过 SICP 一书和 MIT OpenCourseWare 的配套视频来学习,那个时候广泛接触了 Linux 系统自带的各种 Scheme 软件包,在学习计算机一般理论的同时学习 Scheme 语言。我逐渐发现 Scheme 语言本身太简单了,具体的实现又非常多,互相之间区别很大。很多人最终停留在 Scheme 阶段,其中少数有能力的人又自己创造了许多新的 Scheme 实现。但我没有停下来,继续向前走。
4) Common Lisp 阶段I——大学第三年晚期和第四年。学习 Debian 系统自带的 onlisp 和* Common Lisp the Language *电子书,然后用 Debian 自带的 CMU Common Lisp,Steel Bank Common Lisp,GNU Common Lisp 以及 GNU CLISP 等环境来进行 Common Lisp 编程实践。
Debian 里还有几个很大的 Common Lisp 写出的软件,包括 Maxima 和 Axiom 两种数学符号计算系统。CMU Common Lisp (cmucl) 的软件包文档里有 The Evolution of Lisp 这篇著名的论文。我读完以后,顺藤摸瓜通过学校内网的 ACM Digital Library 等论文渠道,把关于 Lisp 语言发展史的关键论文几乎全看了一遍。不过,这个时候还没写出一个像样的 Common Lisp 程序,完全是在学习。
5) Common Lisp 阶段 II——主要是发起自己的开源项目(cl-net-snmp),试图翻译各种 Lisp 资料——最主要的就是 On Lisp 一书。我认为这是一个领域的新手通常会做的两件事。
6) Common Lisp 阶段 III——参与维护别人发起的开源项目(usocket、cl-xml、cl-http、cffi 等),以及试图了解和改进各种 Common Lisp 平台本身的源代码。捎带着参与 Lisp 相关的国际会议,把自己的成果整理成论文,以便跟其他同行建立联系,走向领域前沿。
我现在处在一个新的阶段,并且也走向了 Lisp 领域一条冷门的岔路上:维护前人留下的古老商业 Lisp 软件。我不认为这是一条终极道路,相反这是一条歧途,但我必须去做,因为如果我不做的话,这些有价值的东西就可能失传。我现在的工作与其说是为了谋生和个 人兴趣,还不如说是像一个历史学家一样,在努力地行使保护历史文物的职责。Lisp 领域可谓是浩如烟海,没有其他任何语言具有像 Lisp 这样的深度和广度,也没有哪个语言的程序员可以像 Lisp 程序员那样热爱自己的语言。这是我的观点,但它的真正内涵需要人们自己去体会。
图灵社区:关于编程语言的学习,你有一个很有意思的观点——C和 Lisp 是编程语言的两个极端。可否就此谈谈,并对如何学习编程语言提供一些建议?
田春:这实际是 Paul Graham 在 The roots of Lisp(Lisp 之根源)这篇文章中提出的观点。该文第二段里是这样写的:
“我认为目前为止只有两种真正干净利落, 始终如一的编程模式:C语言模式和 Lisp 语言模式。此二者就像两座高地,在它们中间是尤如沼泽的低地。随着计算机变得越来越强大,新开发的语言一直在坚定地趋向于 Lisp 模式。二十年来,开发新编程语言的一个流行的秘决是,取C语言的计算模式,逐渐地往上加 Lisp 模式的特性,例如运行时类型和无用单元收集。”
我是在同意 Paul Graham 的上述观点的基础上,做出了“C和 Lisp 是编程语言的两个极端”这一评价的。但我的依据除了两种语言的语法风格迥异以外,还考虑了C程序和 Lisp 程序截然不同的运行方式:C程序总是一些零零散散的独立可执行文件,由操作系统把它们拼接在一起;而 Lisp 程序本质上是对 Lisp 环境和 Lisp 语言本身的扩展,Lisp 环境就像一个虚拟机一样,行使着操作系统的职责,把其中加载的所有 Lisp 代码运行起来(Emacs 又何尝不是如此呢)。纵观其他所有语言,我看不出还有本质上的第三种方式了。
图灵社区:我们知道 Common Lisp 是 Lisp 的一门方言,对这门方言的实际应用和未来前景,你有什么看法呢?
田春: Common Lisp 是 Lisp 语言家族中唯一具有工业强度的大型语言,它本身就是为了把之前所有真正用来一般性软件的 Lisp 语言统一起来,尽量兼容它们并消除不一致的地方,最后得到一个完美的集大成体。这个目标事实上确实实现了。1991 年,Common Lisp 发布第一版,至今所有代码几乎可以不经任何修改,就运行在目前还在流行的至少 10 种不同的 Common Lisp 环境上,整整二十年来 Lisp 程序员的成果一直可以正常运行,这对 Lisp 程序员无疑是一种巨大的鼓励。相比之下,其他的语言要么消失了,要么已被改得面目全非。
我的看法是,一个追求卓越的程序员应该广泛尝试多种语言,但如何他真的这样做了,他一定会在遇到 Common Lisp 时停下来,因为他发现这门语言是最强的,也是最美的,并且学习过程也是最艰难的,艰难到以至于学成之后,再没有精力也没有必要去学其他语言了。然后他就会 想尽办法让一切编程事务都用 Common Lisp 来做,最后会奇迹般地发现 Common Lisp 什么都可以干,而且没有哪个领域是干不了的,甚至于没有哪个领域是尚未有 Lisp 程序员踏足的。
至于前景,就像我在《实用 Common Lisp 编程》一书译者序里表达的:一门语言能安全地存活 50 年,那么它就一定可以存活 100 年。人生宝贵,如果希望自己的劳动成果长久流传于世,那么选用 Common Lisp 来表达自己的思想是最稳妥的。
图灵社区:《实用 Common Lisp 编程》的作者,强调了 Lisp 的“可编程性”和“适合探索性编程”。就这本书,他是如何体现这些特色的?这些带来怎样的阅读体验呢?
田春:主要体现在贯穿于书中的实践性章节里。在很多其他语言的类似实践性章节里,可能是把程序的最终版本逐 个部分地向读者做解释,比如这个函数将会完成哪些功能,那个类是做什么用的,诸如此类。但在学习者把所有代码输入电脑之前,程序是几乎跑不起来的。而在 《实用 Common Lisp 编程》一书里,作者借助 Lisp 语言本身的强大优势,采用真正的循序渐进教学法:每一个函数,都从直接可以运行并完成实际功能的简单版本开始,然后再根据逐渐复杂的需求被不断改写;或者 单个函数规模变大以后,再添加新的子函数,诸如此类。这样能够确保学习者每次都能取得阶段性成果,同时演示了 Lisp 程序员们真正写程序时,是如何从零开始,边设计边施工,最后一路积累千上万行代码的。
我自己也写过超过 1 万行代码规模的 cl-net-snmp 项目——一个完整的 SNMP 协议实现。在这个项目里,我甚至做出了 MIB 编译器,把 MIB 定义转译成 Lisp,然后要么解释要么编译加载。这个项目就是从零开始,先解决 ASN.1 各种基本数据类型的 BER 编解码,然后封装 SNMP 数据包,再做 MIB 的语法解析,直到整个服务器和客户端都正常跑起来。Common Lisp 开源社区的同行对我的成果极为称赞,虽然我的代码质量和程序效率还不行,但人们普遍惊讶我可以用 Lisp,将一个看似简单的网络协议以最复杂也最贴近 Lisp 的方式成功实现。学完这本书的实践部分,就可以掌握编写 Lisp 程序的正统思路。然后无论多么复杂的程序,都可以用同样的思路逐渐写出来。
图灵社区:能不能向有志于学习 Common Lisp 的初学者,介绍一些网络资源呢?
田春:所有最重要的网络资源,都写在这本书的最后一章里。但我认为对于初学者来说,看书是最重要的。 Common Lisp the Language (CLTL2) 是最重要的 Common Lisp 语言大全。说起来, 《实用 Common Lisp 编程》一书只涵盖整个语言不到一半的特性。要想写出最专业的代码,必须了解并且灵活组合运用这门语言所给予程序员的所有东西。因此 CLTL2 是一定要看完的,遗憾的是仔细看完这本书至少需要半年。
无论如何,我不推荐人们过早地去参与各种线上讨论,因为 Lisp 社区对新手并不友好,国外的社区尤其是这样,贸然去问各种无聊的问题只会自取其辱。
图灵社区:跟你合作本书的过程中,图灵的编辑都获益良多。在这次的合作之后,你对技术图书的出版,又有哪些看法和建议呢?
田春:这本书得以顺利出版,还是要感谢图灵的编辑们的。尽管这本书 8 月份的时候离出版还遥遥无期,我当时采取了一个手段威胁你们(笑)。不过,有几点我还是不太满意的:一是排版用 Word 太不专业,推荐用 LaTex 排版;二是这本书的最后没有索引,其实索引对这本书比较重要,因为所有粗体的字都是 Common Lisp 的关键字,写代码的人想用某个语句的时候,可以通过索引来查询;三是出版周期还是太长。
至于建议,一是希望图灵的书今后能保留索引,方便读者查阅;二是应在翻译合同中加入出版时间的约定,规定交稿后多长时间出版;三是希望图灵能引进 On Lisp 的版权出版翻译版,我可以提供译稿供出版使用。
图灵社区:感谢田春接受图灵社区的采访,与大家分享自己学习 Lisp 的经历,以及对 Lisp 的看法