我成爲 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。