田春:走在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 的看法
<span id="shareA4" class="fl"> </span>