(譯)「The Little Schemer」── 小眾Schemer?(2010-11-20)

最近在看The Little Schemer,似乎整本書最難的部分就是它字最多的部分──前言。玩笑話,這本書的文字很簡單,但內容很有深度。我試著翻譯了一下(翻譯果然是個苦差事)它“最難的部分”。


前言

為了慶祝Scheme誕生二十周年,我們第三次修訂了The Little LISPer,并將其改名為The Litlle Schemer,這樣更準確一些。我們還寫了它的續(xù)篇:The Seasoned Schemer。

一個程序接收數(shù)據,處理數(shù)據,輸出數(shù)據。要設計一個程序需要對數(shù)據有著透徹的理解。一個優(yōu)秀的程序同時也能反映它要處理的數(shù)據是什么樣子。很多數(shù)據集,也包括很多程序,都是遞歸形式的。遞歸是一種用自己來定義自己或依靠自己來求解自己的方式。

本書的目的就是要教你用遞歸來思考。我們遇到的第一個問題是采用什么語言來闡述這個概念,有三個選擇:自然語言,比如英語;數(shù)學表達;或者程序語言。模棱兩可,不夠準確,甚至冗長,這些在日常交流中自然語言的優(yōu)勢,在介紹遞歸這樣精細的概念時卻變成了劣勢。數(shù)學表達恰恰相反,它可以用極少的符號表達出一個復雜的概念。遺憾地是,數(shù)學表達往往晦澀難懂,只有經過專門的學習才能領會。技術和數(shù)學的結合給了我們一個更理想的選擇──程序語言。我們相信,程序語言是解釋遞歸這一概念的最佳途徑。它繼承了數(shù)學的簡明,但與之不同的是,我們可以運行代碼來觀察它們的行為,并通過不斷地修改來評估這些改動帶來的影響。

Scheme也許是最適合教授遞歸的程序語言了。從Scheme一誕生就支持符號(計算)。程序員不必考慮他自己的語言符號和這些符號在計算機中如何表示。Scheme進行計算最根本的方法就是遞歸。編程最主要的工作就是找出(內在的)遞歸定義。大多數(shù)Scheme實現(xiàn)都采用交互的方式──程序員能立即感知程序的行為并進行調整。當你讀完這本書,最大的感觸可能是,Scheme程序和它要處理的數(shù)據存在著直接的對應。

雖然可以很嚴謹?shù)刂v解Scheme,但理解Scheme并不需要經過專門的數(shù)學訓練。實際上,The Little Schemer出自一門為期兩周的Scheme導論課的授課提綱,這門課是專門為沒接觸過編程,對數(shù)學又沒有絲毫興趣的學生開設的。這些學生大多準備從事公共事務方面的職業(yè)。我們的理念是“用Scheme遞歸地寫出程序,關鍵是要識別出模式”。我們關注的是如何用遞歸的方式編程,因此我們只需用到Scheme中很小的一部分功能:car, cdr, cons, eq?, null?, zero?, add1, sub1, number?, and, or, quote, lambda, define, cond。事實上,這就夠了。

The Little Schemer和它的姊妹篇The Seasoned Schemer不會向你介紹怎么完成現(xiàn)實世界中的任務,但掌握這兩本書中的概念將有助于你更好地理解計算的本質。

閱讀本書之前你必須掌握

讀者應能輕松地閱讀英語,認識數(shù)字,知道計數(shù)。

致謝

……

給讀者的建議

不要匆匆掃過,請仔細閱讀。書里散落著很多有用的提示。試著從不同的側面去理解。按章節(jié)順序讀。如果你還沒有完全弄懂這一章,不要進入下一章,不然你會覺得理解起來很吃力。問題的難度是遞增的,如果你還不能解決前面的問題,后面的題會更無處下手。

在書中,你和我們會就Scheme編程中一些有趣的問題進行討論。如果可以,運行你遇到的例子。Scheme程序很容易讀懂。雖然在不同的Scheme實現(xiàn)之間有一些細微的語法差別(主要是個別名字的拼寫和某些函數(shù)的作用域稍有不同),但Scheme基本上是一致的。要運行書中的Scheme代碼,你還需要定義atom?, sub1, add1.我們會在書里詳細介紹:

(define atom?   
  (lambda (x)  
    (**and** (**not** (pair? x)) (**not** (null? x)))))  

要想知道你的Scheme有沒有正確地定義atom?,運行(atom? (quote())),看是否返回#f。事實上,這個測試也適用于現(xiàn)代的Lisp版本,如Common Lisp。如果用Lisp,你需要添加atom?函數(shù):

(defun atom? (x)   
  (**not** (listp x)))  

你可能需要稍稍修改這程序。書中提供的例子可能都需要做一些修改。在書中,我會在注釋里注明在不同Scheme實現(xiàn)的一些特性。“S:”表示Scheme,“L:”表示Common Lisp。

到第四章,我們會深入探討三個基本的算術操作:add1, sub1, zero?。雖然Scheme沒有提供add1和sub1,但你可以用內置的加減運算符來定義它們。為了避免邏輯上的死結,我們用另一套符號來表示基本的加減操作:+, -(譯注:原書中用的是空心的加號和減號)。

我們不會在書中給出任何標準的定義。我們相信你能自己搞出一套來,這樣比我們給你一個寫好的定義更能讓你記住、理解它們。請好好消化十誡和五律(譯注:書一開始給出的Laws and Commandments)。學習Scheme的關鍵是識別模式。十誡就是對你所見過的模式的總結。書一開始會簡化一些概念。但隨后,它們會被不斷擴展、豐富。你應該知道,這本書里的所有東西都是Scheme,Scheme是一門通用編程語言,不是這樣一本導論性質的書能講清的。在你掌握了本書之后,你可以去讀Scheme中那些進階內容的書。那時,你就能輕松地理解那些內容了。

我們編寫本書時遵循一些約定。不同類別符號的字型稍有不同。變量和原子操作名用斜體。基本數(shù)據,包括數(shù)字和真假的表示,用sans serif字體。關鍵字,比如define, lambda, cond, else, and, or, and quote, 用黑體。如果你要運行書中的程序,可以忽略字型,但要記得看看注解。為了突出字型的作用,注釋里的程序都用typewriter字型。第十章以后,我們將忽略字型的區(qū)別,因為從那章開始,我們會把代碼也看作數(shù)據。
最后談一談斷句。Webster把斷句定義為用標準的符號分割句子來使文意更明確的行為。有時,為了表達清楚,我們會使用非常規(guī)的斷句方式。注意我們不會對左欄的文字(譯注:書采用對話形式,分為左右兩欄)斷句,因為那是程序語言。

我們的例子中經常出現(xiàn)食物的名字,一是因為食物比抽象的符號更好想象(但這不是一本適合在烹飪的時候看的閑書)。我們希望選擇食物作為變量名能有助于你的理解;二是我們想注入一絲樂趣。我們知道這門課會讓你多么沮喪,我們希望這一點點樂趣能緩解你的焦躁。

準備好了嗎。希望你喜歡接下來的挑戰(zhàn)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容