本書適用于那些想更上一層樓的 Lisp 程序員。書中假設(shè)讀者已經(jīng)初步了解 Lisp, 但不要求有豐富的編程經(jīng)驗(yàn)。最初幾章里會(huì)重溫很多基礎(chǔ)知識(shí)。我希望這些章節(jié)也會(huì)讓有經(jīng)驗(yàn)的Lisp 程序員感興趣, 因?yàn)樗鼈円詬湫碌囊暯钦故玖耸熘闹黝}。
通常很難一語道清一門編程語言的精髓, 但 John Foderato 的話已經(jīng)很貼切了:
Lisp 是一門可編程的編程語言。
(Lisp is a programmable programming language.)
這難免以偏概全, 但這種讓 Lisp 隨心而變的能力, 在很大程度上正是 Lisp 專家和新手的不同之處。在自上而下, 把程序逐漸具體化, 用編程語言實(shí)現(xiàn)設(shè)計(jì)的同時(shí), 資深的 Lisp 程序員也實(shí)踐著自底向上的方法, 他們通過創(chuàng)建語言來描述程序的行為。本書教授自底向上編寫程序的方法, 因?yàn)檫@是 Lisp 與生俱來的強(qiáng)項(xiàng)。
隨著軟件復(fù)雜度的增長, 自底向上設(shè)計(jì)的重要性也日益提高。今天的程序可能不得不面對極其復(fù)雜甚至開放式的需求。在這種情況下, 傳統(tǒng)的自上而下方法有時(shí)會(huì)失效。一種新的編程風(fēng)格應(yīng)運(yùn)而生, 它和當(dāng)前大部分計(jì)算機(jī)科學(xué)課程的思路截然不同:
一個(gè)自底向上的程序由一系列的層寫成, 每一層都作為更高一層的編程語言。
X-Window 和 TeX 就是這種程序設(shè)計(jì)風(fēng)格的典范。
本書有兩層主題:
首先, 對以自底向上的方法編制的程序來說, Lisp 語言是不二之選, 反過來, 編寫 Lisp 程序的話, 采用自底向上的編程風(fēng)格也是理所當(dāng)然的。因此《On Lisp》將吸引兩類讀者。對于那些有興趣編寫可擴(kuò)展程序的人, 本書將告訴你如果有了合適的語言, 你能做些什么。對于Lisp 程序員來說, 本書提供了第一手的實(shí)踐指南, 指引他們把 Lisp 的優(yōu)勢發(fā)揮到極致。
本書選用現(xiàn)在的這個(gè)書名是為了強(qiáng)調(diào)自底向上編程對于 Lisp 的重要性。你不再僅僅是用 Lisp 編寫程序, 在 Lisp 之上(OnLisp) , 你可以構(gòu)造自己的語言, 然后再用這個(gè)語言來寫程序。
盡管用任何語言都可以寫出自底向上風(fēng)格的程序, 但 Lisp 對于這種編程風(fēng)格來說是最自然的載體。在 Lisp 里, 自底向上的設(shè)計(jì)并不是那種僅為少見的大型程序或者高難程序服務(wù)的專門技術(shù)。任何規(guī)模的程序都可以在一定程度上以這種方式編寫。Lisp 從一開始就被設(shè)計(jì)成可擴(kuò)展的語言。這種語言本身基本上就是一個(gè)Lisp 函數(shù)的集合, 這些函數(shù)和你自己定義的沒有本質(zhì)區(qū)別。更進(jìn)一步, Lisp 函數(shù)可以表達(dá)成列表, 而列表同時(shí)也是Lisp 的數(shù)據(jù)結(jié)構(gòu)。這就意味著你可以寫出能生成Lisp 代碼的Lisp 函數(shù)。
一個(gè)好的 Lisp 程序員必須懂得如何利用上述這種可能性。通常的途徑是定義一種稱為宏的操作符。駕馭宏是從編寫正確的Lisp 程序走向編寫漂亮的程序過程中最重要的一步。入門級Lisp 書籍給宏留下的篇幅僅限于一個(gè)宏的簡短的概述: 解釋一下宏是什么, 加上幾個(gè)例子蜻蜓點(diǎn)水地提一下, 說能用它實(shí)現(xiàn)一些奇妙的東西。不過本書會(huì)給予這些奇妙的東西特別的重視。這里的目標(biāo)之一就是把所有關(guān)于宏的知識(shí)作一次總結(jié), 在以往, 人們只能從使用宏的經(jīng)驗(yàn)和教訓(xùn)中來吸取這些知識(shí)。
一般來說, Lisp 的入門讀物都不會(huì)強(qiáng)調(diào) Lisp 和其他語言的區(qū)別, 這情有可原。它們必須想辦法把知識(shí)傳授 給那些被教育成只會(huì)用 Pascal 術(shù)語來構(gòu)思程序的學(xué)生。如果非要細(xì)究這些區(qū)別的話, 只會(huì)把問題復(fù)雜化:
例如 defun 雖然看起來像一個(gè)過程定義, 但實(shí)際上, 它是一個(gè)編寫程序的程序, 這個(gè)程序生成了一段代碼, 而這段代碼新建了一個(gè)函數(shù)對象, 然后用函數(shù)定義時(shí)給出的第一個(gè)參數(shù)作為這個(gè)函數(shù)對象的索引。
本書的目的之一就是解釋究竟是什么使Lisp 不同于其他語言。剛落筆時(shí), 我心里明白, 同等條件下自己會(huì)更傾向于用Lisp 而不是 C, Pascal 或 Fortran 來寫程序。我也知道這不只是個(gè)人好惡的問題。但當(dāng)意識(shí)到就要鄭重其事地告訴大家 Lisp 語言在某些方面更優(yōu)秀時(shí), 我發(fā)現(xiàn)應(yīng)該做好準(zhǔn)備, 說說到底為什么。
曾有人問Louis Armstrong 什么是爵士樂, 他答道 "如果你問爵士樂是什么, 那你永遠(yuǎn)不會(huì)知道。" 但他確實(shí)以一種方式回答了這個(gè)問題:他向世人展示了什么是爵士樂。同樣也只有一種方式來解釋Lisp 的威力, 就是演示那些對于其他語言來說極其困難甚至不可能實(shí)現(xiàn)的技術(shù)。多數(shù)關(guān)于編程的書籍, 包括 Lisp 編程書籍, 采用的都是那些你可以用任何其它語言編寫的程序?!禣n Lisp》涉及的多是那些只能用 Lisp 寫的程序。
可擴(kuò)展性, 自底向上程序設(shè)計(jì), 交互式開發(fā), 源代碼轉(zhuǎn)換, 嵌入式語言. 這些都是Lisp 展示其高級特性的舞臺(tái)。
當(dāng)然從理論上講, 任意圖靈等價(jià)的編程語言能做的事, 其它任何語言都可以做到。但這種能力和編程語言的能力卻完全是兩碼事。理論上, 任何你能用編程語言做到的事, 也可以用圖靈機(jī)來做, 但實(shí)際上在圖靈機(jī)上編程得不償失。
所以, 當(dāng)我說這本書是關(guān)于如何做那些其他語言力所不及的事情的時(shí)候, 我并非指數(shù)學(xué)意義上的 "不可能", 而是從編程語言的角度出發(fā)的。這就是說, 如果你不得不用 C 來寫本書中的一些程序, 你可能需要先用 C 寫一個(gè) Lisp 編譯器。舉個(gè)例子, 在 C 語言里嵌入 Prolog 你能想象這需要多少工作量嗎 第 24 章將 說明如何用 180 行 Lisp 做到這一點(diǎn)。
盡管我希望能比單單演示Lisp 的強(qiáng)大之處做得更多。我也想解釋為何 Lisp 與眾不同。這是一個(gè)更微妙的問題, 這個(gè)問題是那么難回答, 它無法使用諸如 "符號計(jì)算" 這樣的術(shù)語來搪塞。我將盡我所學(xué), 盡可能清楚明白地解釋這些問題。
更多建議: