《The Little Schemer:遞歸與函數(shù)式的奧妙》是一本久負(fù)盛名的經(jīng)典之作,兩位作者Daniel P. Friedman、Matthias Felleisen在程序語言界名聲顯赫。《The Little Schemer:遞歸與函數(shù)式的奧妙》介紹了Scheme的基本結(jié)構(gòu)及其應(yīng)用、Scheme的五法十誡、Continuation-Passing-Style、Partial Function、Y-Combinator、Interpreter等內(nèi)容,并通過這些內(nèi)容闡述了計算的一般本質(zhì)。《The Little Schemer:遞歸與函數(shù)式的奧妙》沒有什么理論性描述,所有概念都蘊(yùn)含在獨(dú)特的引導(dǎo)式一問一答過程中,這種方式讓讀者對程序大師運(yùn)用熟稔的程序方法來駕馭概念的能力嘆為觀止。
通過閱讀《The Little Schemer:遞歸與函數(shù)式的奧妙》,可以讓讀者領(lǐng)略遞歸的奧妙、函數(shù)式編程風(fēng)格的魅力。閱讀完畢會有一種意猶未盡的感覺。
《The Little Schemer:遞歸與函數(shù)式的奧妙》適合所有程序員閱讀,特別是函數(shù)式編程愛好者。好好享用!
√ “計算能力是人類大腦讓人興奮的特性之一”——這個觀念直接促生了與眾不同的《The Little Schemer:遞歸與函數(shù)式的奧妙》。作者以極大的熱情、幽默及易于理解的風(fēng)格闡述抽象概念,為樂于探索計算本質(zhì)的人們打開一扇嶄新的思考之門。
√ 《The Little Schemer:遞歸與函數(shù)式的奧妙》將計算作為小學(xué)和高中算術(shù)與代數(shù)知識的擴(kuò)展,并加以闡述。其以遞歸函數(shù)的方式介紹編程,簡要討論計算機(jī)所能發(fā)揮的作用。作者通過獨(dú)特的編程語言、有趣的各式食物來描述這些抽象概念。
√ 多年來,《The Little Schemer:遞歸與函數(shù)式的奧妙》各個版本一直是廣受歡迎的LISP教程。它還出版了法語版和日語版(現(xiàn)在終于有了中文版),已被廣泛證明廣受歡迎。
譯者序
進(jìn)入互聯(lián)網(wǎng)、移動互聯(lián)網(wǎng)時代,軟件開發(fā)方面的好書層出不窮,絕大部分是技術(shù)新、方法新。然而,本書很獨(dú)特,其出版于1995年,至今已有二十余年,而其前身The Little LISPer則出版于1987年,堪稱“古董”!
為什么一本老書還有出版的必要?因為“經(jīng)典”!因為其內(nèi)容揭示了計算的一般本質(zhì),其價值歷經(jīng)時光的檢驗而含金量不減!其實本書已不用過多著墨加以介紹,其在廣大程序員心中早已豎起了一座豐碑。
我酷愛編程,也接觸過許多函數(shù)式編程語言,但沒有任何一種編程語言能夠像LISP那樣擅于通過直接和簡單的方式表達(dá)編程思維,不熟悉者迷惑于它的括號,而登堂入室者則能領(lǐng)略其精髓,最終游刃有余。本書只借助了Scheme編程語言的若干基礎(chǔ)元件,就演繹出了各種問題的解決方式——這就是最佳詮釋!
也許你在工作中不會用到Scheme,但是本書貴在作者深厚的編程積累,并能將豐富的經(jīng)驗充分發(fā)揮到本書內(nèi)容中。全書的每一步都不顯山露水,但最終驀然回首時,輕舟已過萬重山。探索計算本質(zhì)的過程竟然如此巧妙,不禁讓人拍案叫絕——手中用的是Scheme的招式,而心中洞察到的卻是計算的內(nèi)涵!
當(dāng)其他編程書籍在討論大量Hack技巧、各種設(shè)計模式的運(yùn)用、形形色色的語法糖變化的時候,本書無疑就像一部另辟蹊徑的武林秘籍,能大大增強(qiáng)習(xí)練者的內(nèi)功。
作為一名有追求的程序員,這本書就是為你準(zhǔn)備的。同時非常期待本書的姊妹篇The Seasoned Schemer。
參與本書翻譯工作的還有林長瑞、吳桐、朱建寶、周榮華、吳勝華、葉銘輝、李禧強(qiáng)、姚建峰、鄭秀玲。
感謝我的妻子和孩子,他們給了我很大的支持,小寶貝還給我?guī)砹嗽S許多多的樂趣。同時還要感謝本書編輯張春雨,在他的鼓勵下,我的翻譯過程充滿愉悅。
盧俊祥
2017年6月
序
本序最初出現(xiàn)在The Little LISPer 一書的第二、三版中。經(jīng)作者許可,特在此重現(xiàn)。
時光回到1967年,那時我報了一門攝影入門課程。包括我在內(nèi),大多數(shù)參加該課程的同學(xué)都憧憬著早日掌握創(chuàng)造性的攝影知識,希望自己有朝一日能成為又一個愛德華?韋斯頓 。第一天,老師詳細(xì)地列出了一長串這學(xué)期要掌握的技能點(diǎn)。其中一個關(guān)鍵技能是安塞爾?亞當(dāng)斯(Ansel Adams)的“區(qū)域曝光法”——用于預(yù)先視覺化沖印數(shù)據(jù)(最終沖印的灰度),及從景物光線強(qiáng)度中獲取灰度。為了使用區(qū)域曝光法,還得學(xué)習(xí)曝光表用法以度量光線強(qiáng)度,以及通過曝光時間及顯影時間來控制圖像的灰度和對比度。反過來,這些技能又需要諸如膠片安裝、顯影、沖印和藥水調(diào)制等更加底層的技能來支持。你必須學(xué)會將感光材料的顯影過程程序化,以便在日后處理中獲得一致的效果。第一次實驗課是設(shè)法識別滑滑的顯影劑和刺鼻的定影液。
而要讓構(gòu)圖更具創(chuàng)造性,則必須首先具備駕馭工具的能力。甚至在能力具備之前都不要去構(gòu)思如何組織一張好照片。在工程領(lǐng)域,如同其他創(chuàng)造性藝術(shù),必須學(xué)會分析以支持我們在各方面的努力。那些有關(guān)鋼材、揚(yáng)塵以及大量數(shù)學(xué)方法等方面的知識,是計算構(gòu)筑物屬性時需要的,缺失了這些知識就無法構(gòu)建美觀而實用的橋梁。同樣,未深入理解如何“預(yù)先視覺化”編程生成的工序,則無法構(gòu)造出卓越的計算機(jī)系統(tǒng)。
一些攝影師選擇8×10的黑白底片 ,而其他一些則選擇35mm的底片 。不同片幅類型的底片各有其優(yōu)缺點(diǎn)。跟攝影一樣,編程也需要選擇稱心的語言。魔法編程語言Lisp屬于崇尚自由和靈活風(fēng)格的程序員!Lisp最初的設(shè)想是作為理論輔助工具,用于遞歸理論及符號代數(shù)。時至今日,Lisp已發(fā)展成為一個軟件開發(fā)工具的大家族,魅力獨(dú)特、功能強(qiáng)大且異常靈活,為軟件系統(tǒng)的快速原型設(shè)計提供了全方位支持。與其他編程語言一樣,技術(shù)社區(qū)開發(fā)出龐大的抽象功能庫,Lisp則將這些功能連接起來。在Lisp的世界里,程序是一等數(shù)據(jù),以參數(shù)方式傳遞,以值的方式返回,并存儲在數(shù)據(jù)結(jié)構(gòu)中。這種靈活性極具價值,而最重要的是,其為形式化、命名以及精簡慣用法——工程設(shè)計中必不可少的常用使用模式,提供了機(jī)制保障。此外,Lisp程序能夠輕松操縱Lisp程序的表述——一個開發(fā)龐大結(jié)構(gòu)的程序綜合 及分析工具(如交叉引用)的支持特性。
The Little LISPer一書以獨(dú)特方式闡述了Lisp創(chuàng)造性編程哲學(xué)里的精髓技法。全書借助大量實際訓(xùn)練——掌握構(gòu)建遞歸過程及操縱遞歸數(shù)據(jù)結(jié)構(gòu)等技能所必要的實踐,相當(dāng)巧妙地將知識組織起來,讓人絲毫感受不到學(xué)習(xí)的壓力。The Little LISPer一書對Lisp學(xué)習(xí)者的意義,不亞于哈農(nóng) 手指練習(xí)或車爾尼 鋼琴研究對于鋼琴學(xué)生的意義。
杰拉德?杰伊?薩斯曼
劍橋(美國,馬薩諸塞州)
前言
為了給Scheme二十周年慶祝生日,我們第三次修訂了The Little LISPer,這次我們把書名改為更貼切的The Little Schemer,并增寫了姊妹篇:The Seasoned Schemer。
程序接受數(shù)據(jù)并產(chǎn)生數(shù)據(jù)。程序設(shè)計需要徹底理解數(shù)據(jù);好的程序會反映出所處理數(shù)據(jù)的結(jié)構(gòu)。大多數(shù)的數(shù)據(jù)集合,并由此延伸到大多數(shù)程序,都是可遞歸表示的。遞歸是依據(jù)自身定義對象或解決問題的方法。
本書的目標(biāo)是引導(dǎo)讀者學(xué)習(xí)遞歸思維模式。我們首先需要確定與遞歸概念搭檔的語言。這里有三種相對明確的選擇:自然語言,如英語;形式化的數(shù)學(xué)語言;或者是編程語言。自然語言易產(chǎn)生歧義、不嚴(yán)謹(jǐn)且有時候拖沓冗長。這可能在人們?nèi)粘=涣鲿r沒什么問題,但對于簡明闡述遞歸這樣的嚴(yán)謹(jǐn)概念,這些特征就容易出問題。數(shù)學(xué)語言則與自然語言相反:其僅通過一些符號就能表述強(qiáng)大的形式化概念。但很不幸,除非接受過數(shù)學(xué)專業(yè)訓(xùn)練,否則一般人理解不了數(shù)學(xué)語言。技術(shù)與數(shù)學(xué)的結(jié)合帶給了我們第三種選擇—幾乎是最理想的選擇:編程語言。我們相信編程語言是表達(dá)遞歸概念的最佳方式。編程語言像數(shù)學(xué)那樣,具備將形式化含義賦予一系列符號的能力。但又不同于數(shù)學(xué),可以直接體驗編程語言—可以運(yùn)行本書中的程序,觀察其行為,然后修改它,再看看修改效果。
Scheme大概是用來講解遞歸概念的最佳編程語言。符號化是Scheme的天然特質(zhì)—程序員不必過多考慮所用語言符號與計算機(jī)表述形式之間的關(guān)聯(lián)。遞歸是Scheme的天然計算機(jī)制;主要的Scheme編程任務(wù)是創(chuàng)建(可能的)遞歸定義。Scheme程序主要用于交互—程序員可以立即運(yùn)行代碼并觀察結(jié)果。此外,至本書結(jié)束時,我們收獲的最大感悟應(yīng)該是:Scheme程序結(jié)構(gòu)與程序所操縱數(shù)據(jù)之間是直接對應(yīng)的 。
雖然Scheme程序可以以一種非常形式化的方式來描述,但理解Scheme并不需要特別的數(shù)學(xué)知識。實際上,本書基于一個Scheme兩周“速成”介紹課程的講義整理而成,該課程針對那些沒有編程經(jīng)驗且不喜歡數(shù)學(xué)的學(xué)生。這些學(xué)生中有許多人正準(zhǔn)備從事公共事務(wù)方面的工作。我們的信條是:用Scheme遞歸地編寫程序本質(zhì)上是簡單的模式識別(Pattern Recognition)。由于我們唯一關(guān)心的是遞歸編程,因此我們僅在Scheme的幾個招式上下功夫:car、cdr、cons、eq?、null?、zero?、add1、sub1、number?、and、or、quote、lambda、define以及cond。事實上,我們選擇了完美的Scheme編程語言—我們的程序才能如此簡潔。
The Little Schemer和The Seasoned Schemer并未涉足應(yīng)用編程領(lǐng)域,但掌握書中的概念則為你打開了理解計算本質(zhì)的大門。
閱讀須知
你應(yīng)該具備文字閱讀能力,識得數(shù)字,還要會數(shù)數(shù)。
致謝
我們要感謝眾多貢獻(xiàn)者及他們?yōu)楸緯诙⑷嫣峁┑膸椭8兄xBruce Duba、Kent Dybvig、Chris Haynes、Eugene Kohibecker、Richard Salter、George Springer、Mitch Wand和David S. Wise的無數(shù)次討論,為全書內(nèi)容構(gòu)思提供了思路。感謝Ghassan Abbas、Charles Baker、David Boyer、Mike Dunn、Terry Falkenberg、Rob Friedman、John Gateley、Mayer Goldberg、Iqbal Khan、Julia Lawall、Jon Mendelsohn、John Nienart、Jeffrey D. Perotti、Ed Robertson、Anne Shpuntoff、Erich Smythe、Guy Steele、Todd Stein和Larry Weisselberg在草稿階段提供了許多重要意見。尤其感謝Bob Filman反復(fù)審核并提出深刻而尖銳的批評。最后,感謝Nancy Garrett、Peg Fletcher和Bob Filman為設(shè)計與TeX排版做出的貢獻(xiàn)。
最新的第4版受惠于Dorai Sitaram的Scheme排版程序—無比智能的SLATEX。Kent Dybvig的Chez Scheme讓Scheme編程變得非常愉快。真誠感謝Shelaswau Bushnell、Richard Cobbe、David Combs、Peter Drake、Kent Dybvig、Rob Friedman、Steve Ganz、Chris Haynes、Erik Hilsdale、Eugene Kohlbecker、Shriram Krishnamurthi、Julia Lawall、Suzanne Menzel Collin McCurdy、John Nienart、Jon Rossie、Jonathan Sobel、George Springer、Guy Steele、John David Stone、Vikram Subramaniam、Mitch Wand以及Melissa Wingard-Phillips的批評與建議。
讀者指南
閱讀本書切勿走馬觀花、一味圖快。請仔細(xì)閱讀,金玉珠璣分散在書中各個角落。本書很重要,重要的書至少讀三遍。閱讀時做到一步一個腳印。在未完全理解一章之前,不要嘗試跳到下一章。問題按難度遞增排序;解決不了早先的問題,后面的問題則將更難回答。
本書以對話方式組織內(nèi)容,涉及Scheme程序的樣例趣談時,對話將在你(讀者)和我們(作者)之間進(jìn)行。請盡可能動手試驗閱讀到的樣例代碼。獲取Scheme是一件很容易的事。盡管在不同Scheme實現(xiàn)之間存在微小語法差異(主要是特殊名稱和特定函數(shù)方面的拼寫),但Scheme語法基本上是一致的。接下來要玩轉(zhuǎn)Scheme,還得定義本書引入的atom?、sub1和add1:
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
試一試(atom? (quote ())),看看其是否返回#f,以驗證Scheme正確定義了atom?。實際上,該概念同樣適用于諸如Common Lisp這樣的現(xiàn)代Lisp方言。在Lisp中要以函數(shù)方式定義atom?:
(defun atom? (x)
(not (listp x)))
此外,你可能還需要對書中的程序進(jìn)行稍加修改。典型的,只是做個別變化。框格注釋 會給出程序試驗的建議。“S:”打頭的注釋代表Scheme相關(guān)內(nèi)容,“L:”打頭的注釋代表Common Lisp相關(guān)內(nèi)容。
第4章我們會通過3個運(yùn)算函數(shù):add1、sub1和zero?來開發(fā)一個基本的算術(shù)程序。由于Scheme并未提供add1和sub1,因此需要借助內(nèi)建的加減基本元件來定義它們。進(jìn)一步的,為了避免沖突,程序的加減法必須以不同的符號:+和—來分別實現(xiàn) 。
本書不涉及任何形式化定義。我們相信你可以構(gòu)建自己的定義,并因而記住及理解這些定義,這樣的效果比我們一口口喂給你吃要好。但在你出山之前,需確保自己徹底理解了Scheme的五法十誡 。學(xué)習(xí)Scheme的鑰匙是“模式識別”。Scheme十誡心法指出了具體模式。在本書的早期,一些概念出于簡單起見講解得比較淺顯;但隨著內(nèi)容的深入,將適時展開描述。你應(yīng)該也知道,雖然全書講的是Scheme,但Scheme自身應(yīng)用的廣泛性,可不是我們用介紹性文字就能夠清晰闡述的。在掌握了本書內(nèi)容之后,就可以著手閱讀與理解更加全面且高級的其他Scheme書籍了。
我們的大量示例都跟食物有關(guān),這里有兩個原因。首先,食物比抽象符號更形象(你如果正在節(jié)食,顯然不適合讀這本書,開玩笑)。我們希望各種食物能夠幫助你理解示例及相關(guān)概念。其次,我們打算亂一下你的心智。我們知道學(xué)習(xí)之路總是充滿各種沮喪,一點(diǎn)點(diǎn)障礙將有助你保持清醒。
你可以整裝待發(fā)了。祝你好運(yùn)!希望你好好享受荊棘旅程中的激情挑戰(zhàn)。
祝你胃口大開!
丹尼爾?弗里德曼
馬提亞?費(fèi)雷森
Daniel P. Friedman,是美國印第安那大學(xué)計算機(jī)科學(xué)系的教授。Matthias Felleisen是美國萊斯大學(xué)計算機(jī)科學(xué)系的教授。同時,他們使用Scheme來教授計算及編程課程的經(jīng)驗超過了25年,發(fā)表了100多篇論文,出版了3部Scheme相關(guān)書籍。
盧俊祥,程序員;譯者,愛讀書;武當(dāng)二十八式太極拳。
第1章 玩具總動員 2
第2章 處理,處理,反復(fù)處理…… 14
第3章 用cons構(gòu)筑恢宏 32
第4章 數(shù)字游戲 58
第5章 我的天!都是星星 80
第6章 如影隨形 96
第7章 朋友及關(guān)系 110
第8章 Lambda終結(jié)者 124
第9章 ……周而復(fù)始…… 148
第10章 值是什么 174
幕間休息 192
索引 194