鮑勃大爺:為何選擇Clojure?

banq發表於2019-08-23

我用許多不同的語言編寫了系統; 從彙編程式到Java。我用二進位制機器語言編寫程式。我用Fortran,COBOL,PL / 1,C,Pascal,C ++,Java,Lua,Smalltalk,Logo和其他幾十種語言編寫了應用程式。我使用了靜態型別語言,有很多型別推斷。我用過無型別語言。我使用了動態型別語言。我使用了像Forth這樣的基於堆疊的語言,以及像Prolog這樣的基於邏輯的語言。

在過去的五十年裡,我使用了很多不同的語言。(應該改稱鮑勃大爺)
我得出了一個結論。
我最喜歡的語言是Lisp, 我認為這種語言將比其他語言更耐用,我相信這種語言最終將成為所有程式設計師使用的標準語言......

我不是Lisp的粉絲。40年來,我不是Lisp的粉絲。我看到CARs和CDRs和CADDADDRs,並認為這只是學術上的胡扯; 有趣但不是真正有用。
然後,十年前我找到了SICP。之後我找到了Clojure。Clojure是一個Lisp,它位於Java生態系統之上(並且沒有CARs或CDRs或CADADAADRs)。
我沒有立刻相信Clojure。花了幾年時間。但是在經常磕磕絆絆和沮喪之後,我開始意識到這種語言是我用過的最簡單,最優雅,最不那麼強大的語言 - 而且不是很小。

那麼,為什麼這麼看好Clojure?我已經列了一份清單。你準備好了嗎?

1. 表達經濟
如果您想知道這份清單列表的其餘部分在哪裡,那是存在的,這就是原因,只有一個。
在Clojure中編寫富有表現力的程式碼更簡單,更容易,更少遮擋。它需要更少的行。它需要更少的字元。它需要更少的時間。它需要較少的心理體操。

為什麼會這樣?答案很簡單。的確答案是:非常簡單。

該語言幾乎沒有語法或語法

解釋這一點的最佳方法可能是向您展示一個例子。所以,在這裡,為了您的娛樂,是列印前25個整數方塊的程式:

(println (take 25 (map #(* % %) (range))))


我們來看看這裡的語法:
  • ( 意思是:開始一個list。
  • ) 意思是:list結束。
  • 名稱就是名稱,在這種情況下都是函式。
  • * 是乘法函式的名稱。
  • # 表示:將下一個list解釋為函式。
  • % 意思是:該函式的第一個引數。

你剛剛看到Clojure語法的80%左右。

首先是那個“(”符號。這意味著它與“)” 之間的所有內容都是一個list。在大多數情況下,Clojure將list解釋為函式呼叫。在這種情況下,函式是println。這只是類似我們習慣用Java 的System.out.println。

我們傳遞的是println什麼?我們傳遞了take函式的結果。該take函式需要兩個引數。第一個25是take的專案數;第二個引數是一個list。因此,這個take函式將返回一個list,其中包含第二個引數中list的前25項。

第二個引數中的list是什麼?這是呼叫map函式的結果。該map函式需要兩個引數。第一個是函式,第二個是list。該map函式將返回一個list,該list是在傳入list的每個元素上呼叫傳入函式的結果。

傳入map的函式是什麼?它是由建立的匿名函式,它只是簡單地呼叫它複製的第一個引數,這是%的意思。

什麼list被傳入map?它是透過呼叫range函式返回的list,該range函式只返回“所有”非負整數的list列表。該列表是惰性的,因此實際上只會生成上游函式所需的整數。

有些人不喜歡%語法的複雜性,所以我們可以建立一個square函式如下:

(defn square [x] (* x x))
(println (take 25 (map square (range))))


defn定義了一個名為square新函式,括號[]定義了一種稱為向量的不同型別的“list列表”。list列表具有連結列表的執行時複雜性。向量具有陣列的執行時複雜性。無論如何,在這種情況下,向量告訴defn該square函式需要一個名為的引數x。其餘你應該能夠推斷出來。
這使第二行更好一些理解。該map函式只是呼叫square。
現在你已經看到了Clojure大約90%的語法。
現在讓我們將它與等效的Java程式進行比較:

public class SquaresOfIntegers {
  public static void main(String[] args) {
    for (int i=0; i<25; i++)
      System.out.println(i*i);
  }
}

(banq注:被Java洗腦的我一眼看到這份程式碼,頓然一目瞭然,一下子明白了,Clojure表達的那麼擰巴,Clojure和Java大概是文言文和白話文的區別,文言文確實很簡單,讀懂文言文的人惜字如金)

即使你不計算封閉的類,這也更加冗長。然而,更重要的是,這涵蓋了大約5%的Java語法。並且不要讓我開始與C ++進行比較。

現在我不想說明這一點。經過與語言之後的語言比較,我可以繼續比較。底線是Clojure的語法比大多數語言小得多。這種最小的語法意味著我能夠比大多數其他語言更清楚,更直接地表達問題。

看,我很難啊。我當時是一名C ++程式設計師。更重要的是,我(不再是)是一名C ++語言律師。我沉迷於該語言的重量級語法。我被所有可愛的“fidelty bits”迷住了。二十年前,我發現向Java過渡到相當“meh”。它只是一個精簡的C ++(它之後變得更加肥胖)。

但是我向Clojure的過渡令人大開眼界。基於輕量級語法,我希望它適用於一些課堂練習,但不適用於構建大型系統。在我看來,大型系統等同於大型語法。孩子,我錯了。

相反,我發現Clojure的最小語法比Java或C ++的更重的語法更有利於構建大型系統。事實上,這不是一場競賽。構建大型系統是Clojure比我使用的任何其他語言更簡單,更容易。

正如我在開始時指出的那樣,我使用了很多語言。

但是關於…?
所以你可能有一些抱怨,問題,異議等等。讓我看看我是否可以預料到它們:

我的天啊!所有這些括號
你幾歲啊…?睜開大眼看看,這是一個java函式呼叫:f(x)。現在這裡是Clojure中相應的函式呼叫:(f x)。你在那裡看到任何額外的括號嗎?
好的,嘻嘻,這不完全公平。我們最後會看到一些括號,但那只是因為我們傾向於巢狀函式呼叫。看看上面的整數程式,你會明白為什麼。不要擔心,如果你真的不喜歡那種巢狀語法,你總是可以使用執行緒宏(讓讀者理解)。

但是不是很慢嗎?
不,Clojure並不慢。哦,看,它不是C.它不是彙編程式。如果納秒是您的關注,那麼您可能不希望Clojure在您最內層的迴圈中。您可能也不想要Java或C#。但是我們現在編寫的99.9%的軟體不需要納秒效能。我使用Clojure 構建了一個基於GUI的實時動畫太空戰遊戲。即使螢幕上有數百個物體,我也可以將幀速率保持在20s 。Clojure並不慢。

但是Javascript怎麼樣?
ClojureScript編譯到Javascript並在瀏覽器中執行就好了。實際上,我上面提到的太空戰計劃是使用ClojureScript編譯的,並且在瀏覽器中以比本機模式更高的幀率執行(我還在試圖解決這個問題。)

但它是動態型別的!
動態型別必須寫測試,不是嗎?作為測試的一部分,您可以使用clojure/spec庫來指定型別的模式,並使用前置條件和後置條件(按合同樣式設計)進行動態檢查,讓您心滿意足。

但它是動態型別的[2] !!
型別宣告是需要語法成本的。而語法成本的加入會降低表達的經濟性。

但是,Dammit,它是動態型別的!
好的我明白了。你喜歡靜態型別。很好,你可以使用一個很好的靜態型別語言,我將使用Clojure。我們之前還在蘇格蘭呢。

那IDE呢?
帶有Cursive外掛的IntelliJ非常好用。大多數Clojure程式設計師使用Emacs。

重構怎麼樣?
帶有Cursive的IntelliJ有一些很好的重構; 雖然他們還沒有“提取方法”(來吧夥計!)

Java互操作怎麼樣?
沒問題。Clojure程式可以直接呼叫Java。Java程式只需要一點點修改就可以呼叫Clojure程式。Interop不應該是您關注的問題。

我在哪裡可以找到Clojure程式設計師?​​​​​​​
他們在那裡; 但你最好還是編寫它們。語法很簡單。您可能已經知道Java平臺。只需決定在Clojure中構建您的下一個系統。花一兩個星期習慣這門語言。然後開始哦,當你在幾個月的時間裡,你會意識到你早期的東西是多麼原始,你會被誘惑去清理它。但還有什麼是新的?

但是那是一種新語言.
是的,每個月都有新的語言。每週。每天。我們不乏新語言。關於這些新語言的事情是,任何一種語言都沒有新的東西。它們只是由他們在一個罐子裡切割和震動的舊語言組成,然後在Yahtzee的語言遊戲中拋棄。
好的,那不完全公平。在語言空間中仍有一些好的想法滲透。但這些想法都不是革命性的。我們進入了“調整”的時代。我沒有發現任何新語言幾乎與Clojure一樣引人注目,僅僅因為幾乎所有語言都具有額外的語法。

其他語言的語法也很少。為什麼不能成為選擇之一?
是的,這是真的。Forth有一個很小的語法。Smalltalk也是如此。但是這兩種語言都有自己的包袱。Forth是一種字尾表示式(將運算子寫在運算元之後) 語言。Forth的短語並不是表達經濟。雖然我發現基於它的PostScript很有趣。
Smalltalk小而優雅,美麗。它催生了設計模式革命。它催生了重構革命。它催生了TDD革命。它有助於產生敏捷革命。Smalltalk是一種具有巨大影響力的語言。
Smalltalk也是一種基於影像的語言。很少有程式設計師能夠將自己的想法包含在真正意義上的內容中。不幸的是,與所有基於文字檔案的語言相比,語言萎縮了。
到目前為止,Lisp比Smalltalk或Forth更老。它建立於1957年,源自30年代的概念,並且從未像Smalltalk和Forth那樣萎靡不振。的確,這是拒絕死亡的語言。我們試圖殺了很多次。但就像令人討厭的鄰居流浪貓一樣,它會......繼續......回來。
最後,Lisp功能齊全。未來看起來非常實用。​​​​​​​
 

相關文章