第一章 函數(shù)和數(shù)據(jù)
1.1導(dǎo)引
這一章講通過(guò)一些內(nèi)建的Lisp函數(shù)例子還對(duì)函數(shù)和數(shù)據(jù)的表示法做一個(gè)概覽烘浦。假如你已經(jīng)有一些其他語(yǔ)言的編程經(jīng)驗(yàn)玫芦,你可以在幾分鐘內(nèi)跳讀這一章,你會(huì)看到一些有字符組成的運(yùn)算函數(shù),一個(gè)Lisp的關(guān)鍵數(shù)據(jù)類型撤摸,一些以yes或者no為結(jié)果的斷言温眉。當(dāng)你認(rèn)為你已經(jīng)完全領(lǐng)會(huì)了全部?jī)?nèi)容之后們可以閱讀概述那一章節(jié)來(lái)檢驗(yàn)一下自己是不是真的理解了缸匪。
假如你是一個(gè)編程新手,那這一章就是專門為你設(shè)計(jì)的芍殖,我們將開(kāi)始解釋什么是函數(shù)什么是數(shù)據(jù)豪嗽。數(shù)據(jù)的意思可以稱作信息,例如數(shù)字,單詞和一系列事物龟梦。你可以想象一個(gè)函數(shù)就像一個(gè)盒子隐锭,而數(shù)據(jù)從盒子的中間流過(guò)。函數(shù)以某一種方式操作數(shù)據(jù)计贰,然后結(jié)果就是輸出的數(shù)據(jù)钦睡。
在介紹了Lisp提供的一些內(nèi)建函數(shù)之后,我們將學(xué)習(xí)如何將現(xiàn)有的函數(shù)組合在一起創(chuàng)造出一個(gè)新的函數(shù)(其實(shí)這就是計(jì)算機(jī)編程的本質(zhì))躁倒。引述出一些十分有用的創(chuàng)造函數(shù)的技巧和方法荞怒。
1.2操作數(shù)字的函數(shù)
或許大家最熟悉的函數(shù)就是簡(jiǎn)單地?cái)?shù)學(xué)運(yùn)算函數(shù),加減乘除秧秉。下圖體現(xiàn)的就是兩個(gè)數(shù)如何相加:
這個(gè)函數(shù)的名字是“+”褐桌,我們可以用幾種方式來(lái)描述,在上圖中到底發(fā)生了什么象迎。從數(shù)據(jù)的觀點(diǎn)來(lái)看荧嵌,數(shù)字2和3流入到函數(shù)中,然后數(shù)字5從函數(shù)中流出砾淌。從函數(shù)的觀點(diǎn)來(lái)看啦撮,函數(shù)“+”接受數(shù)字2和3作為輸入,然后產(chǎn)生5作為結(jié)果輸出汪厨。從程序員的角度來(lái)看赃春,我們調(diào)用或者說(shuō)喚起函數(shù)“+”,輸入是3和3劫乱,然后函數(shù)返回值5.這些都是用不同的方式討論數(shù)據(jù)和程序是等同的织中;你將在本書(shū)的許多地方遇到這個(gè)觀點(diǎn)。
下表表示的就是Lisp函數(shù)對(duì)數(shù)字的操作:
符號(hào) | 意義 |
---|---|
+ | 計(jì)算出兩個(gè)數(shù)加在一起的值 |
- | 取得第一個(gè)數(shù)減去第二個(gè)數(shù)的值 |
* | 計(jì)算兩個(gè)數(shù)相乘得到的值 |
/ | 計(jì)算第一個(gè)數(shù)被第二個(gè)數(shù)除得到的值 |
ABS | 計(jì)算一個(gè)數(shù)的絕對(duì)值 |
SQRT | 求一個(gè)數(shù)的根 |
讓我們來(lái)看另一個(gè)數(shù)據(jù)流穿過(guò)函數(shù)的例子要拂。ABS抠璃,輸出絕對(duì)值的函數(shù),顧名思義脱惰,正數(shù)不變搏嗡,負(fù)數(shù)取反的函數(shù)。
數(shù)字-4輸入到函數(shù)ABS拉一,計(jì)算出來(lái)的絕對(duì)值作為結(jié)果輸出4采盒。
1.3三種數(shù)字類型
在本書(shū)中,我們打的交道最多的是正數(shù)(integers)蔚润,就是所有的自然數(shù)字磅氨。Common Lisp也提供了許多其他種類的數(shù)字。應(yīng)該了解的一種就是浮點(diǎn)數(shù)(floating point numbers)嫡纠。一個(gè)浮點(diǎn)數(shù)總是會(huì)被寫(xiě)成帶有一個(gè)十進(jìn)制的小數(shù)點(diǎn)烦租;例如延赌,數(shù)字5會(huì)被寫(xiě)成5.0。這個(gè)SQRT函數(shù)一般來(lái)講是返回一個(gè)浮點(diǎn)數(shù)作為結(jié)果叉橱,就算輸入是整數(shù)的情況下也是挫以。
分?jǐn)?shù)(ratio)是另一種數(shù)字形式。在便攜式計(jì)算器中窃祝,1/2的表示常常是浮點(diǎn)數(shù)來(lái)表示的比如0.5掐松。但是在Common Lisp中,我們也可以吧二分之一表示成1/2粪小。Common Lisp把分?jǐn)?shù)自動(dòng)簡(jiǎn)化成為最小分母的形式大磺;例如分?jǐn)?shù)4/6,6/9,都會(huì)被簡(jiǎn)化成2/3探膊。
當(dāng)我們調(diào)用一個(gè)運(yùn)算函數(shù)杠愧,并輸入一個(gè)整數(shù)的時(shí)候,Common Lisp通常將會(huì)產(chǎn)生一個(gè)整數(shù)形式或者分?jǐn)?shù)形式的結(jié)果突想。假如我們的輸入時(shí)整數(shù)浮點(diǎn)數(shù)混合殴蹄,結(jié)果就將會(huì)是一個(gè)浮點(diǎn)數(shù)。
1.4輸入的順序是十分重要的
按照慣例猾担,當(dāng)我們說(shuō)函數(shù)的“第一個(gè)”輸入的時(shí)候,我們指的是函數(shù)盒子左邊最頂上的那個(gè)箭頭刺下。那“第二個(gè)”輸入就是那個(gè)次高的箭頭绑嘹,以此類推。輸入的順序?qū)τ诤瘮?shù)來(lái)說(shuō)是非常重要的橘茉。舉個(gè)例子工腋,8除以2和2除以8是不一樣的。
當(dāng)8除以2的時(shí)候畅卓,結(jié)果是4擅腰,而2除以8的時(shí)候,結(jié)果是1/4翁潘。另外有一點(diǎn)趁冈,在這里的分?jǐn)?shù)并不一定是小于1的。
1.5字符串(SYMBOLS)
字符串是Lisp中另一種類型的數(shù)據(jù)拜马。大家會(huì)發(fā)現(xiàn)他們比數(shù)字會(huì)更有趣一些渗勘。字符串是典型的跟隨英語(yǔ)單詞來(lái)的(比如TUESDAY),還有詞組(比如BUFFALO-BREATH)俩莽,或者約定俗成的縮寫(xiě)(就像SQRT是“square root”的縮寫(xiě))旺坠。字符串命名幾乎包含了實(shí)際上所有的字母和數(shù)字的組合。加上一些特殊字符扮超,比如連字符-取刃。這里有一些Lisp字符串的例子:
X
ZORCH
BANANAS
R2D2
COMPUTER
WINDOW-WASHER
LORETTA
WARP-ENGINES
ABS
GARBANZO-BEANS
YAER-TO-DATE
BEEBOP
甚至可以寫(xiě)得很長(zhǎng)
ANTIDISESTABLISHMENTARIANISM
你可能注意到了在這些字符串中包含了一些數(shù)字蹋肮,比如“R2D2”,但是這不足以讓他們成為數(shù)字璧疗。很重要的一件事情就是分清楚數(shù)字特別是整數(shù)和字符的區(qū)別坯辩,他們的定義會(huì)有幫助理解:
整數(shù):由“0”到“9”組成的序列,可以選擇“+”或者“-”作為前綴病毡。
字符:任何字母濒翻,數(shù)字,和被允許使用的特殊字符(不包括數(shù)字)組成的序列啦膜。
所以FOUR是一個(gè)字符串有送,而4就是一個(gè)整數(shù),+4也是一個(gè)整數(shù)僧家,但是+就是一個(gè)字符串雀摘。而且7-11也是一個(gè)字符串。
1.6 特殊的字符串
T Truth八拱,真阵赠,表示“yes”
NIL 表示假“no”
T和NIL在Lisp中是基礎(chǔ)不過(guò)的感念,以至于你問(wèn)一個(gè)專業(yè)的Lisp程序員yesorno的問(wèn)題肌稻,得到的回答往往不是英語(yǔ)清蚀,而是T和NIL。(“老王爹谭!去吃飯唄枷邪?”“NIL,剛吃了”)更重要的是說(shuō)诺凡,詳實(shí)的Lisp函數(shù)回答問(wèn)題的答案也是T或者NIL东揣。這樣yesorno的問(wèn)題被稱作斷言(predicates)。
1.7 一些簡(jiǎn)單的斷言
一個(gè)斷言就是一個(gè)回答問(wèn)題的函數(shù)腹泌。斷言的輸出是固定的嘶卧,在回答yes的時(shí)候輸出T,回答no的時(shí)候輸出NIL凉袱。我們將要學(xué)習(xí)的第一個(gè)斷言是判斷輸入是不是一個(gè)數(shù)字芥吟。名字叫做NUMBERP(讀作“number-pee”,就是“Number predicate”的簡(jiǎn)寫(xiě)):
相似的绑蔫,斷言SYMBOLP就是測(cè)試輸入是不是一個(gè)字符串运沦,是的話就返回T,不是的話就返回NIL配深。
斷言ZEROP携添,EVENP和ODDP只接受數(shù)字作為輸入,如果輸入是0的篓叶,ZEROP返回T烈掠。
如果輸入是奇數(shù)的話羞秤,ODDP將會(huì)返回T,否則將會(huì)返回NIL左敌。而斷言EVENP怎是判斷偶數(shù)瘾蛋。
到現(xiàn)在為止,你應(yīng)該注意到凡是后綴P的函數(shù)名一般都是斷言矫限。(“老王哺哼!餓P?”“T叼风,餓爆了”)雖說(shuō)不是所有斷言都遵守這個(gè)規(guī)律取董,但是大部分是的。
還有兩個(gè)斷言:<返回T无宿,如果第一個(gè)輸入大于第二個(gè)輸入茵汰。(這兩個(gè)也是我們后綴P規(guī)律的第一個(gè)例外)。
1.8 EQUAL斷言
斷言EQUAL是用來(lái)比較兩個(gè)輸入是不是相同孽鸡。如果兩個(gè)輸入相同蹂午,EQUAL返回T,反之則返回NIL彬碱。在Common Lisp中的斷言與EQUAL功能近乎相同的斷言有EQ豆胸,EQL和 EQUALP,他們之間的區(qū)別還不會(huì)困擾我們,對(duì)于初學(xué)者巷疼,EQUAL是第一個(gè)需要掌握的配乱。
附注:第一章比較長(zhǎng),(上)到這里經(jīng)原始函數(shù)講完了皮迟,(下)開(kāi)始講組合函數(shù)。