Clojure與Lisp
"Lisp 不是一門語言骤坐,它是一種構(gòu)建素材。" (艾倫·凱)
"任何C或Fortran程序復(fù)雜到一定程度之后,都會(huì)包含一個(gè)臨時(shí)開發(fā)的、只有一半功能的弟翘、不完全符合規(guī)格的虫腋、到處都是bug的、運(yùn)行速度很慢的Common Lisp實(shí)現(xiàn)稀余。"(格林斯潘第十定律(Greenspun's Tenth Rule))
Clojure是一門Lisp方言(Lisp dialect).
Lisp 是一種編程語言悦冀,以表達(dá)性和功能強(qiáng)大著稱,但人們通常認(rèn)為它不太適合應(yīng)用于一般情況滚躯。Clojure 是一種運(yùn)行在 Java? 平臺(tái)上的 Lisp 方言雏门,它的出現(xiàn)徹底改變了這一現(xiàn)狀嘿歌。如今掸掏,在任何具備 Java 虛擬機(jī)的地方,都可以利用 Lisp 的強(qiáng)大功能宙帝。
Clojure 是完全的,真正意義上的神圣的lisp語言的一個(gè)方言.
lisp語言因?yàn)槠錈o以倫比強(qiáng)大能力和幾乎無窮的表達(dá)力而獲得了盛譽(yù),Clojure自然也不例外. 它的功能和元編程的能力是建立在這樣的基礎(chǔ)之上的:異常馴服的C語言的"石頭" 或 具有 延展性的java語言的"木頭" . 你可以用幾百行甚至幾十行Clojure代碼取替代幾千行靜態(tài)語言 的代碼,伴隨著這而來的是bug數(shù)量的減少和開發(fā)時(shí)間的縮短.
樣板代碼(Boilerplate code )被完全刪去. 域指定語言(Domain Specific Languages ) 不僅 簡(jiǎn)單,而且更一般化--lisp程序往往是按照 "自下而上" 的開發(fā)方式寫成的. 展開式(演進(jìn)式)的 結(jié)構(gòu)和語法更適合特定的問題領(lǐng)域. 你在程序運(yùn)行的時(shí)候取修改程序,而不需要重新編譯或重啟 程序.
但是,歷史上也有對(duì)lisp進(jìn)行詆毀的人,或許稱為抱怨更為合適. lisp發(fā)展過程中,沒有完整的規(guī)范, 各種不兼容的實(shí)現(xiàn),陳舊落伍的限制.cruft accumulate 在其存在的四五十年里一直存在. 對(duì)于 大多數(shù)人來說,它的語法過于詭異了.
Clojure 修正上面的大多數(shù)這些問題. 它保留了 lisp 的思想和哲學(xué),并同時(shí)清除了過去的很多限制. Clojure 高速丧凤、干凈、具有優(yōu)先能力和優(yōu)雅的特征. 但是沒有改變lisp中 "代碼也是數(shù)據(jù)" 的哲學(xué). Clojure 語言在直覺和觀感上比歷史上的lisp更易于閱讀. 在后面開始學(xué)習(xí)的初級(jí)階段,你就發(fā)現(xiàn)雖然 仍有各種括號(hào),但是代碼是難以置信的容易讀和寫.
對(duì)于那些熟悉lisp語言的人來說,他們很快就會(huì)發(fā)現(xiàn)他們非常適應(yīng)Clojure.
Lisp簡(jiǎn)史
1958年步脓,John McCarthy設(shè)計(jì)了Lisp語言
20世紀(jì)50年代中期愿待,在大多數(shù)計(jì)算機(jī)處理的都是數(shù)值數(shù)據(jù)等,包括語言學(xué)靴患、心理學(xué)和數(shù)學(xué)領(lǐng)域上一些人們開始對(duì)人工智能產(chǎn)生了興趣仍侥。覺得必須實(shí)現(xiàn)共同需要的一個(gè)方法,使計(jì)算機(jī)能夠處理鏈表中的符號(hào)數(shù)據(jù)鸳君,允許語言的處理农渊、信息存入和檢索、定理證明的過程機(jī)器化或颊。IBM是首先對(duì)人工智能開發(fā)有興趣的商業(yè)機(jī)構(gòu)之一砸紊。
1958年夏天,來自麻省理工學(xué)院的人工智能研究先驅(qū)約翰·麥卡錫(John McCarthy)參與IBM資訊研究部的工作囱挑,研究符號(hào)運(yùn)算及應(yīng)用需求醉顽。可是平挑,IBM旗下的Fortran表處理語言卻未能支援符號(hào)運(yùn)算的遞歸游添、條件表達(dá)式、動(dòng)態(tài)存儲(chǔ)分配及隱式回收等功能通熄。約翰·麥卡錫于1958年秋季回到麻省理工學(xué)院后唆涝,和Marvin Minsky組成了人工智能項(xiàng)目。開展一個(gè)表處理軟件系統(tǒng)來實(shí)現(xiàn)McCarthy提出建議采納者程序的工作棠隐,爾后推動(dòng)了表處理語言LISP的誕生石抡。
1960年4月,麥卡錫在ACM雜志發(fā)表了一片文章《遞回函數(shù)的符號(hào)表達(dá)式以及由機(jī)器運(yùn)算的方式助泽,第一部》.
自1960代末年至1980年初年啰扛,各種更新LISP版本涌現(xiàn)嚎京,有源自加利福尼亞大學(xué)伯克利分校的Franz Lisp、在AutoCAD運(yùn)行的AutoLISP前身XLISP隐解、猶他大學(xué)開展的Standard Lisp及Portable Standard Lisp鞍帝、專屬于Lisp機(jī)器上運(yùn)行的ZetaLisp、源自法國(guó)國(guó)家信息與自動(dòng)化研究所的LeLisp煞茫、以及MIT人工智能實(shí)驗(yàn)室的Gerald Sussman與Guy Steele所開發(fā)的Scheme等帕涌。
1984年,改良自MacLisp续徽、集各版本大成蚓曼、跨平臺(tái)、且被目為事實(shí)標(biāo)準(zhǔn)的Common Lisp誕生钦扭。至1994年纫版,美國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì)(ANSI)對(duì)Common Lisp語言進(jìn)行了標(biāo)準(zhǔn)化。
自穩(wěn)定運(yùn)行的Common Lisp出現(xiàn)起客情,再有各機(jī)構(gòu)按各自所需而開展后續(xù)Lisp其弊,包括1990年來自歐洲用戶的EuLisp、運(yùn)行于Java虛擬機(jī)的Clojure膀斋、受到Maclisp影響而創(chuàng)的Emacs Lisp梭伐、以及自由開源來自卡內(nèi)基·梅隆大學(xué)的CMUCL、還有IsLisp仰担,Racket糊识,ACL2等蓬勃涌現(xiàn)。
自2000年起惰匙,LISP共享者合力支援的自由開源社區(qū)逐漸形成技掏,致力于LISP后續(xù)發(fā)展。
當(dāng)前最新潮的編程語言项鬼,只是實(shí)現(xiàn)了他在1958年的設(shè)想而已哑梳。
這怎么可能呢?計(jì)算機(jī)技術(shù)的發(fā)展绘盟,不是日新月異嗎鸠真?1958年的技術(shù),怎么可能超過今天的水平呢龄毡?
這是因?yàn)镴ohn McCarthy本來沒打算把Lisp設(shè)計(jì)成編程語言吠卷,至少不是我們現(xiàn)在意義上的編程語言。他的原意只是想做一種理論演算沦零,用更簡(jiǎn)潔的方式定義圖靈機(jī)祭隔。
所以,為什么上個(gè)世紀(jì)50年代的編程語言路操,到現(xiàn)在還沒有過時(shí)疾渴?簡(jiǎn)單說千贯,因?yàn)檫@種語言本質(zhì)上不是一種技術(shù),而是數(shù)學(xué)搞坝。數(shù)學(xué)是不會(huì)過時(shí)的搔谴。
Lisp語言就好比是快速排序(Quicksort)算法,這種算法是1960年提出的,至今仍然是最快的通用排序方法桩撮。
Lisp的思想
Lisp語言誕生的時(shí)候敦第,就包含了9種新思想。其中一些我們今天已經(jīng)習(xí)以為常店量,另一些則剛剛在其他高級(jí)語言中出現(xiàn)芜果,至今還有2種是Lisp獨(dú)有的。按照被大眾接受的程度垫桂,這9種思想依次是:
1 條件結(jié)構(gòu)(即"if-then-else"結(jié)構(gòu))
現(xiàn)在大家都覺得這是理所當(dāng)然的师幕,但是Fortran I就沒有這個(gè)結(jié)構(gòu)粟按,它只有基于底層機(jī)器指令的goto結(jié)構(gòu)诬滩。
2 函數(shù)也是一種數(shù)據(jù)類型
在Lisp語言中,函數(shù)與整數(shù)或字符串一樣灭将,也屬于數(shù)據(jù)類型的一種疼鸟。它有自己的字面表示形式(literal representation),能夠儲(chǔ)存在變量中庙曙,也能當(dāng)作參數(shù)傳遞空镜。一種數(shù)據(jù)類型應(yīng)該有的功能,它都有捌朴。
3 遞歸
Lisp是第一種支持遞歸函數(shù)的高級(jí)語言吴攒。
4 變量的動(dòng)態(tài)類型
在Lisp語言中,所有變量實(shí)際上都是指針砂蔽,所指向的值有類型之分洼怔,而變量本身沒有。復(fù)制變量就相當(dāng)于復(fù)制指針左驾,而不是復(fù)制它們指向的數(shù)據(jù)镣隶。
5 垃圾回收機(jī)制
6 程序由表達(dá)式(expression)組成
Lisp程序是一些表達(dá)式區(qū)塊的集合,每個(gè)表達(dá)式都返回一個(gè)值诡右。
7 符號(hào)(symbol)類型
符號(hào)實(shí)際上是一種指針安岂,指向儲(chǔ)存在哈希表中的字符串。
8 代碼使用符號(hào)和常量組成的樹形表示法(notation)
9 無論什么時(shí)候帆吻,整個(gè)語言都是可用的
Lisp并不真正區(qū)分讀取期域那、編譯期和運(yùn)行期。你可以在讀取期編譯或運(yùn)行代碼猜煮;也可以在編譯期讀取或運(yùn)行代碼次员;還可以在運(yùn)行期讀取或者編譯代碼样眠。
在讀取期運(yùn)行代碼,使得用戶可以重新調(diào)整(reprogram)Lisp的語法翠肘;
在編譯期運(yùn)行代碼檐束,則是Lisp宏的工作基礎(chǔ);
在運(yùn)行期編譯代碼束倍,使得Lisp可以在Emacs這樣的程序中被丧,充當(dāng)擴(kuò)展語言(extension language);
在運(yùn)行期讀取代碼绪妹,使得程序之間可以用S-表達(dá)式(S-expression)通信甥桂,近來XML格式的出現(xiàn)使得這個(gè)概念被重新"發(fā)明"出來了。
Lisp的宏
Lisp語言剛出現(xiàn)的時(shí)候邮旷,它的思想與其他編程語言大相徑庭黄选。后者的設(shè)計(jì)思想主要由50年代后期的硬件決定。隨著時(shí)間流逝婶肩,流行的編程語言不斷更新?lián)Q代办陷,語言設(shè)計(jì)思想逐漸向Lisp靠攏。
思想1到思想5已經(jīng)被廣泛接受律歼,思想6開始在主流編程語言中出現(xiàn)民镜,思想7在Python語言中有所實(shí)現(xiàn),不過似乎沒有專用的語法险毁。
思想8可能是最有意思的一點(diǎn)制圈。它與思想9只是由于偶然原因,才成為L(zhǎng)isp語言的一部分畔况,因?yàn)樗鼈儾粚儆贘ohn McCarthy的原始構(gòu)想鲸鹦,是由他的學(xué)生Steve Russell自行添加的。它們從此使得Lisp看上去很古怪跷跪,但也成為了這種語言最獨(dú)一無二的特點(diǎn)馋嗜。
Lisp古怪的形式,倒不是因?yàn)樗恼Z法很古怪域庇,而是因?yàn)樗緵]有語法嵌戈,程序直接以解析樹(parse tree)的形式表達(dá)出來。在其他語言中听皿,這種形式只是經(jīng)過解析在后臺(tái)產(chǎn)生熟呛,但是Lisp直接采用它作為表達(dá)形式。它由列表構(gòu)成尉姨,而列表則是Lisp的基本數(shù)據(jù)結(jié)構(gòu)庵朝。
用一門語言自己的數(shù)據(jù)結(jié)構(gòu)來表達(dá)該語言,這被證明是非常強(qiáng)大的功能。思想8和思想9九府,意味著你可以寫出一種能夠自己編程的程序椎瘟。這可能聽起來很怪異,但是對(duì)于Lisp語言卻是再普通不過侄旬。最常用的做法就是使用宏肺蔚。
術(shù)語"宏"在Lisp語言中,與其他語言中的意思不一樣儡羔。Lisp宏無所不包宣羊,它既可能是某樣表達(dá)式的縮略形式,也可能是一種新語言的編譯器汰蜘。如果你想真正地理解Lisp語言仇冯,或者想拓寬你的編程視野,那么你必須學(xué)習(xí)宏族操。
如果你創(chuàng)造了一種新語言苛坚,其中有car、cdr色难、cons泼舱、quote、cond莱预、atom柠掂、eq這樣的功能,還有一種把函數(shù)寫成列表的表示方法依沮,那么在它們的基礎(chǔ)上,你完全可以推導(dǎo)出Lisp語言的所有其他部分枪狂。事實(shí)上危喉,Lisp語言就是這樣定義的,John McCarthy把語言設(shè)計(jì)成這個(gè)樣子州疾,就是為了讓這種推導(dǎo)成為可能辜限。
Clojure簡(jiǎn)介
運(yùn)行于Java虛擬機(jī)的List方言Clojure.
Lisp是一種以表達(dá)性和功能強(qiáng)大著稱的編程語言,但人們通常認(rèn)為它不太適合應(yīng)用于一般情況严蓖,而Clojure的出現(xiàn)徹底改變了這一現(xiàn)狀薄嫡。如今,在任何具備 Java 虛擬機(jī)的地方颗胡,都可以使用 Lisp 的強(qiáng)大功能毫深。
Clojure 是一種函數(shù)式編程語言
它囊括了函數(shù)式編程的所有精華:
避免了不穩(wěn)定狀態(tài)、遞歸毒姨、更高階的函數(shù)等哑蔫。
Clojure 還是一個(gè)動(dòng)態(tài)類型的語言
我們可以選擇添加類型信息來提高代碼中的關(guān)鍵路徑的性能。
Clojure 不僅可在 JVM 上運(yùn)行,而且可以與Java無縫融合(JVM平臺(tái)的語言家族原則上都支持)的互操作性闸迷。最后嵌纲,Clojure 在設(shè)計(jì)上也考慮了并發(fā)性,并具有并發(fā)編程的一些獨(dú)特特性腥沽。
Clojure的設(shè)計(jì)原則
(1)簡(jiǎn)單: 鼓勵(lì)純函數(shù)逮走,極簡(jiǎn)的語法(少數(shù)special form),個(gè)人也認(rèn)為clojure不能算是多范式的語言(有部分OO特性)今阳,為了支持多范式引入的復(fù)雜度言沐,我們?cè)贑++和Scala身上都看到了。
(2)專注:前綴運(yùn)算符不需要去考慮優(yōu)先級(jí)酣栈,也沒有什么菱形繼承的問題险胰,動(dòng)態(tài)類型系統(tǒng)(有利有弊),REPL提供的探索式編程方法(告別修改/編譯/運(yùn)行的死循環(huán)矿筝,所見即所得)起便。
(3)實(shí)用:前面提到,構(gòu)建在JVM之上窖维,跟Java語言的互操作非常容易榆综。直接調(diào)用Java方法,不去發(fā)明一套新的調(diào)用語法铸史,努力規(guī)避Java語言中繁瑣的地方(doto,箭頭宏等等)鼻疮。
(4)清晰:純函數(shù)(前面提到),immutable var琳轿,immutable數(shù)據(jù)結(jié)構(gòu)判沟,STM避免鎖問題。不可變減少了心智的負(fù)擔(dān)崭篡,降低了多線程編程的難度挪哄,純函數(shù)也更利于測(cè)試和調(diào)試。
(5)一致:語法的一致性:例如doseq和for宏類似琉闪,都支持destructring,支持相同的guard語句(when,while)迹炼。數(shù)據(jù)結(jié)構(gòu)的一致性:sequence抽象之上的各種高階函數(shù)。
光劍說
Clojure有著獨(dú)特的吸引力颠毙,首先因?yàn)樗荓ISP —— 一門富有傳奇色彩的語言斯入,一直希望有機(jī)會(huì)可以學(xué)習(xí)一門LISP的方言;
其次Clojure是一門接地氣的語言蛀蜜,它運(yùn)行在JVM這個(gè)最成功刻两、應(yīng)用最廣泛平臺(tái)之上,能夠跟Java代碼無縫互操作涵防,JVM上所有資源都可以為Clojure所用闹伪。
Clojure是這樣的有潛力沪铭、接地氣,那么如果你要選擇一門新語言來玩玩偏瓤,不選它選什么杀怠?