Clojure與Lisp

Clifford004 8年前發布 | 98K 次閱讀 Lisp Clojure Lisp開發

Clojure與Lisp

"Lisp 不是一門語言,它是一種構建素材。" (艾倫·凱)

"任何C或Fortran程序復雜到一定程度之后,都會包含一個臨時開發的、只有一半功能的、不完全符合規格的、到處都是bug的、運行速度很慢的Common Lisp實現。"(格林斯潘第十定律(Greenspun's Tenth Rule))

Clojure是一門Lisp方言(Lisp dialect).

Lisp 是一種編程語言,以表達性和功能強大著稱,但人們通常認為它不太適合應用于一般情況。Clojure 是一種運行在 Java? 平臺上的 Lisp 方言,它的出現徹底改變了這一現狀。如今,在任何具備 Java 虛擬機的地方,都可以利用 Lisp 的強大功能。

Clojure 是完全的,真正意義上的神圣的lisp語言的一個方言.

lisp語言因為其無以倫比強大能力和幾乎無窮的表達力而獲得了盛譽,Clojure自然也不例外. 它的功能和元編程的能力是建立在這樣的基礎之上的:異常馴服的C語言的"石頭" 或 具有 延展性的java語言的"木頭" . 你可以用幾百行甚至幾十行Clojure代碼取替代幾千行靜態語言 的代碼,伴隨著這而來的是bug數量的減少和開發時間的縮短.

樣板代碼(Boilerplate code )被完全刪去. 域指定語言(Domain Specific Languages ) 不僅 簡單,而且更一般化--lisp程序往往是按照 "自下而上" 的開發方式寫成的. 展開式(演進式)的 結構和語法更適合特定的問題領域. 你在程序運行的時候取修改程序,而不需要重新編譯或重啟 程序.

但是,歷史上也有對lisp進行詆毀的人,或許稱為抱怨更為合適. lisp發展過程中,沒有完整的規范, 各種不兼容的實現,陳舊落伍的限制.cruft accumulate 在其存在的四五十年里一直存在. 對于 大多數人來說,它的語法過于詭異了.

Clojure 修正上面的大多數這些問題. 它保留了 lisp 的思想和哲學,并同時清除了過去的很多限制. Clojure 高速、干凈、具有優先能力和優雅的特征. 但是沒有改變lisp中 "代碼也是數據" 的哲學. Clojure 語言在直覺和觀感上比歷史上的lisp更易于閱讀. 在后面開始學習的初級階段,你就發現雖然 仍有各種括號,但是代碼是難以置信的容易讀和寫.

對于那些熟悉lisp語言的人來說,他們很快就會發現他們非常適應Clojure.

Lisp簡史

1958年,John McCarthy設計了Lisp語言

20世紀50年代中期,在大多數計算機處理的都是數值數據等,包括語言學、心理學和數學領域上一些人們開始對人工智能產生了興趣。覺得必須實現共同需要的一個方法,使計算機能夠處理鏈表中的符號數據,允許語言的處理、信息存入和檢索、定理證明的過程機器化。IBM是首先對人工智能開發有興趣的商業機構之一。

1958年夏天,來自麻省理工學院的人工智能研究先驅約翰·麥卡錫(John McCarthy)參與IBM資訊研究部的工作,研究符號運算及應用需求。可是,IBM旗下的Fortran表處理語言卻未能支援符號運算的遞歸、條件表達式、動態存儲分配及隱式回收等功能。約翰·麥卡錫于1958年秋季回到麻省理工學院后,和Marvin Minsky組成了人工智能項目。開展一個表處理軟件系統來實現McCarthy提出建議采納者程序的工作,爾后推動了表處理語言LISP的誕生。

1960年4月,麥卡錫在ACM雜志發表了一片文章《遞回函數的符號表達式以及由機器運算的方式,第一部》.

自1960代末年至1980年初年,各種更新LISP版本涌現,有源自加利福尼亞大學伯克利分校的Franz Lisp、在AutoCAD運行的AutoLISP前身XLISP、猶他大學開展的Standard Lisp及Portable Standard Lisp、專屬于Lisp機器上運行的ZetaLisp、源自法國國家信息與自動化研究所的LeLisp、以及MIT人工智能實驗室的Gerald Sussman與Guy Steele所開發的Scheme等。

1984年,改良自MacLisp、集各版本大成、跨平臺、且被目為事實標準的Common Lisp誕生。至1994年,美國國家標準學會(ANSI)對Common Lisp語言進行了標準化。

自穩定運行的Common Lisp出現起,再有各機構按各自所需而開展后續Lisp,包括1990年來自歐洲用戶的EuLisp、運行于Java虛擬機的Clojure、受到Maclisp影響而創的Emacs Lisp、以及自由開源來自卡內基·梅隆大學的CMUCL、還有IsLisp,Racket,ACL2等蓬勃涌現。

自2000年起,LISP共享者合力支援的自由開源社區逐漸形成,致力于LISP后續發展。

當前最新潮的編程語言,只是實現了他在1958年的設想而已。

這怎么可能呢?計算機技術的發展,不是日新月異嗎?1958年的技術,怎么可能超過今天的水平呢?

這是因為John McCarthy本來沒打算把Lisp設計成編程語言,至少不是我們現在意義上的編程語言。他的原意只是想做一種理論演算,用更簡潔的方式定義圖靈機。

所以,為什么上個世紀50年代的編程語言,到現在還沒有過時?簡單說,因為這種語言本質上不是一種技術,而是數學。數學是不會過時的。

Lisp語言就好比是快速排序(Quicksort)算法,這種算法是1960年提出的,至今仍然是最快的通用排序方法。

Lisp的思想

Lisp語言誕生的時候,就包含了9種新思想。其中一些我們今天已經習以為常,另一些則剛剛在其他高級語言中出現,至今還有2種是Lisp獨有的。按照被大眾接受的程度,這9種思想依次是:

1 條件結構(即"if-then-else"結構)

現在大家都覺得這是理所當然的,但是Fortran I就沒有這個結構,它只有基于底層機器指令的goto結構。

2 函數也是一種數據類型

在Lisp語言中,函數與整數或字符串一樣,也屬于數據類型的一種。它有自己的字面表示形式(literal representation),能夠儲存在變量中,也能當作參數傳遞。一種數據類型應該有的功能,它都有。

3 遞歸

Lisp是第一種支持遞歸函數的高級語言。

4 變量的動態類型

在Lisp語言中,所有變量實際上都是指針,所指向的值有類型之分,而變量本身沒有。復制變量就相當于復制指針,而不是復制它們指向的數據。

5 垃圾回收機制

6 程序由表達式(expression)組成

Lisp程序是一些表達式區塊的集合,每個表達式都返回一個值。

7 符號(symbol)類型

符號實際上是一種指針,指向儲存在哈希表中的字符串。

8 代碼使用符號和常量組成的樹形表示法(notation)

9 無論什么時候,整個語言都是可用的

Lisp并不真正區分讀取期、編譯期和運行期。你可以在讀取期編譯或運行代碼;也可以在編譯期讀取或運行代碼;還可以在運行期讀取或者編譯代碼。

在讀取期運行代碼,使得用戶可以重新調整(reprogram)Lisp的語法;

在編譯期運行代碼,則是Lisp宏的工作基礎;

在運行期編譯代碼,使得Lisp可以在Emacs這樣的程序中,充當擴展語言(extension language);

在運行期讀取代碼,使得程序之間可以用S-表達式(S-expression)通信,近來XML格式的出現使得這個概念被重新"發明"出來了。

Lisp的宏

Lisp語言剛出現的時候,它的思想與其他編程語言大相徑庭。后者的設計思想主要由50年代后期的硬件決定。隨著時間流逝,流行的編程語言不斷更新換代,語言設計思想逐漸向Lisp靠攏。

思想1到思想5已經被廣泛接受,思想6開始在主流編程語言中出現,思想7在Python語言中有所實現,不過似乎沒有專用的語法。

思想8可能是最有意思的一點。它與思想9只是由于偶然原因,才成為Lisp語言的一部分,因為它們不屬于John McCarthy的原始構想,是由他的學生Steve Russell自行添加的。它們從此使得Lisp看上去很古怪,但也成為了這種語言最獨一無二的特點。

Lisp古怪的形式,倒不是因為它的語法很古怪,而是因為它根本沒有語法,程序直接以解析樹(parse tree)的形式表達出來。在其他語言中,這種形式只是經過解析在后臺產生,但是Lisp直接采用它作為表達形式。它由列表構成,而列表則是Lisp的基本數據結構。

用一門語言自己的數據結構來表達該語言,這被證明是非常強大的功能。思想8和思想9,意味著你可以寫出一種能夠自己編程的程序。這可能聽起來很怪異,但是對于Lisp語言卻是再普通不過。最常用的做法就是使用宏。

術語"宏"在Lisp語言中,與其他語言中的意思不一樣。Lisp宏無所不包,它既可能是某樣表達式的縮略形式,也可能是一種新語言的編譯器。如果你想真正地理解Lisp語言,或者想拓寬你的編程視野,那么你必須學習宏。

如果你創造了一種新語言,其中有car、cdr、cons、quote、cond、atom、eq這樣的功能,還有一種把函數寫成列表的表示方法,那么在它們的基礎上,你完全可以推導出Lisp語言的所有其他部分。事實上,Lisp語言就是這樣定義的,John McCarthy把語言設計成這個樣子,就是為了讓這種推導成為可能。

Clojure簡介

運行于Java虛擬機的List方言Clojure.

Lisp是一種以表達性和功能強大著稱的編程語言,但人們通常認為它不太適合應用于一般情況,而Clojure的出現徹底改變了這一現狀。如今,在任何具備 Java 虛擬機的地方,都可以使用 Lisp 的強大功能。

Clojure 是一種函數式編程語言

它囊括了函數式編程的所有精華:

避免了不穩定狀態、遞歸、更高階的函數等。

Clojure 還是一個動態類型的語言

我們可以選擇添加類型信息來提高代碼中的關鍵路徑的性能。

Clojure 不僅可在 JVM 上運行,而且可以與Java無縫融合(JVM平臺的語言家族原則上都支持)的互操作性。最后,Clojure 在設計上也考慮了并發性,并具有并發編程的一些獨特特性。

Clojure的設計原則

(1)簡單: 鼓勵純函數,極簡的語法(少數special form),個人也認為clojure不能算是多范式的語言(有部分OO特性),為了支持多范式引入的復雜度,我們在C++和Scala身上都看到了。

(2)專注:前綴運算符不需要去考慮優先級,也沒有什么菱形繼承的問題,動態類型系統(有利有弊),REPL提供的探索式編程方法(告別修改/編譯/運行的死循環,所見即所得)。

(3)實用:前面提到,構建在JVM之上,跟Java語言的互操作非常容易。直接調用Java方法,不去發明一套新的調用語法,努力規避Java語言中繁瑣的地方(doto,箭頭宏等等)。

(4)清晰:純函數(前面提到),immutable var,immutable數據結構,STM避免鎖問題。不可變減少了心智的負擔,降低了多線程編程的難度,純函數也更利于測試和調試。

(5)一致:語法的一致性:例如doseq和for宏類似,都支持destructring,支持相同的guard語句(when,while)。數據結構的一致性:sequence抽象之上的各種高階函數。

光劍說

Clojure有著獨特的吸引力,首先因為它是LISP —— 一門富有傳奇色彩的語言,一直希望有機會可以學習一門LISP的方言;

其次Clojure是一門接地氣的語言,它運行在JVM這個最成功、應用最廣泛平臺之上,能夠跟Java代碼無縫互操作,JVM上所有資源都可以為Clojure所用。

Clojure是這樣的有潛力、接地氣,那么如果你要選擇一門新語言來玩玩,不選它選什么?

 

來自: https://segmentfault.com/a/1190000005824577

 

 本文由用戶 Clifford004 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!