03.16 6 個新奇的編程方式,改變你對編碼的認知

編譯自:Reddit

我時不時會發現一種編程語言的不同用法它有時候會改變我對編程的看法啊。這篇文章中,我想分享一下讓我驚訝的發現。這不是類似於高呼“函數式編程會改變世界!”博客文章。我敢打賭,大多數讀者都沒有聽說過下面的大多數語言和範例,所以你應該也會被這些新概念吸引。

注意:我對以下大多數語言的使用經驗都很少,但是我發現他們背後的想法非常吸引人,但對其沒有專業知識,所以有任何錯誤請指出並指導更正。如果您也有新的範例和想法,歡迎分享。

默認併發

6 個新奇的編程方式,改變你對編碼的認知

示例語言:ANI, Plaid

讓我們用一個哲學家的思想來解決問題吧:有些編程語言是默認情況下併發的,也就是說,每行代碼都是並行執行的。

例如,假設你寫了三行代碼,A,B和C:

6 個新奇的編程方式,改變你對編碼的認知

在大多數編程語言中,A先執行,然後執行B,最後執行C。在像ANI這樣的語言中,A,B和C都將同時執行。

ANI中代碼行之間的控制流或排序,僅僅是代碼行之間顯式依賴關係的副作用。例如,如果B引用了A中定義的變量,則A和C將同時執行,而B只會在A完成後執行。

以下是ANI中的“Hello World”示例:

6 個新奇的編程方式,改變你對編碼的認知

在ANI術語中,我們將"Hello, World!"對象(字符串)發送到std.out流。如果我們發送另一個字符串,會發生 std.out什麼

6 個新奇的編程方式,改變你對編碼的認知

這兩行代碼並行執行,因此它們可以在控制檯中以任何順序結束。現在,看看當我們在一行上引入一個變量並參考它會發生什麼:

6 個新奇的編程方式,改變你對編碼的認知

第一行聲明一個“鎖存(latch)”(鎖存器有點像變量),調用 s它包含一個字符串; 第二行將文本賦值 "Hello, World!"給s; 第三行“解鎖” s並將內容發送給std.out。在這裡,您可以看到ANI的隱式程序排序:由於每行都依賴於前一行,因此此代碼將按寫入的順序執行。

Plaid 語言還聲稱通過默認支持併發性,但使用權限模型,如在本文中,設置控制流程。多核技術正在興起,併發性仍然是大多數語言中難點。ANI 和 Plaid 提供了一個新的解決方案,可以帶來驚人的性能提升;,問題在於“默認並行”是否會改變開發的狀態。有關更多信息,請參閱併發性並行性。

相關類型

6 個新奇的編程方式,改變你對編碼的認知

示例語言:Idris, Agda, Coq

你可能習慣使用C和Java等語言來鍵入系統,編譯器可以檢查變量是整數,列表還是字符串。但是如果你的編譯器能檢查一個變量是“一個正整數”,“一個長度為2的列表”還是“一個迴文字符串”呢?

下面是如何聲明一個Vector包含無形庫1,2,3的值:

6 個新奇的編程方式,改變你對編碼的認知

這將創建一個變量l1,它的類型簽名不僅指定它Vector是包含的Ints,而且指定它的Vector長度為3.編譯器可以使用此信息來捕獲錯誤。讓我們使用該vAdd方法在Vector兩個之間執行成對加法Vectors:

6 個新奇的編程方式,改變你對編碼的認知

上面的例子工作正常,因為類型系統知道兩者 Vectors都有長度3.但是,如果我們嘗試了vAdd 兩種Vectors不同的長度,我們沒等到運行時就會在編譯時得到一個錯誤。

6 個新奇的編程方式,改變你對編碼的認知

Shapeless 是一個仍然有點粗糙的庫,只支持依賴類型的一個子集,並有相當冗長的代碼和類型簽名。相反,Idris使得類型成為編程語言的第一類成員,因此依賴類型系統似乎更加強大和乾淨。為了進行比較,請查看Scala vs Idris:相關類型,現在以及未來的討論。

連貫語言

6 個新奇的編程方式,改變你對編碼的認知

示例語言:Forth, cat,joy

有沒有想過不用變量和函數應用程序編程會是什麼樣子?至少我沒有,但顯然有些人這麼想了,他們提出了連續編程。這個想法是,語言中的所有內容都是將數據推送到堆棧或從堆棧中彈出數據的函數; 程序幾乎完全通過功能組合(串聯組合)來構建。

這聽起來很抽象,所以我們來看看cat中的一個簡單例子 :

6 個新奇的編程方式,改變你對編碼的認知

在這裡,我們將兩個數字推入堆棧,然後調用該+函數,將兩個數字從堆棧中彈出,並將其添加到堆棧中的結果:代碼的輸出為5。下面是一個稍微有趣的示例:

6 個新奇的編程方式,改變你對編碼的認知

讓我們一行一行地瀏覽一下:

  1. 首先,我們聲明一個函數foo。請注意,cat中的函數沒有指定輸入參數:所有參數都從堆棧中隱式讀取。

  2. foo調用

  3. 接下來,我們將值0和42輸入堆棧:我們將它們包括在括號中以確保它們未被執行就推入堆棧。這是因為它們將分別用於調用if下一行函數的“then”和“else”分支。

  4. 該if函數從堆棧中彈出3個項目:布爾條件,“then”分支和“else”分支。根據布爾條件的值,它會將“then”或“else”分支的結果輸回堆棧。

  5. 最後,我們將20輸入堆棧並調用foo函數。

  6. 當所有的事情都做完後,會得到一個42的結果

這種編程風格頗有趣味:程序可以以無數種方式拆分和連接以創建新程序; 非常簡單的語法(甚至比LISP更簡單),導致非常簡潔的程序; 也具有強大的元編程支持。看起來你必須記住或想象堆棧的當前狀態,而不是能夠從代碼中的變量名稱中讀取它,這可能使得很難推斷代碼。

6 個新奇的編程方式,改變你對編碼的認知

示例語言:Prolog, SQL

聲明式編程已經存在了很多年,但大多數程序員仍然不知道這個概念。這裡的要點是:在大多數主流語言中,你需要描述如何解決一個特定的問題; 在聲明性語言中,你只需描述你想要的結果,而語言本身就能找出到達那裡的方法。

例如,如果您在C中從頭開始編寫排序算法,例如編寫合併排序的指令,該指令逐步描述如何遞歸地將數據集分成一半並按排序順序合併到一起。

如果您使用像Prolog這樣的聲明性語言對數字進行排序 ,則應該描述所需的輸出:“我需要相同的值列表,但索引中的每個項目 i應小於或等於索引處的項目i + 1”。將以前的C解決方案與此Prolog代碼進行比較:

6 個新奇的編程方式,改變你對編碼的認知

如果你使用過SQL,那麼你已經完成了一種聲明式編程,你可能沒有意識到這一點:當你發出查詢時select X from Y where Z,你正在描述你想要返回的數據集;它是真正計算出如何執行查詢的數據庫引擎。

聲明性語言的美妙之處在於它允許你在更高層次的抽象中工作:你只需要描述所需輸出的規範。例如,prolog中簡單數獨求解器的代碼,只是列出瞭解決的數獨謎題的每行,每列和對角線應該是什麼樣的:

6 個新奇的編程方式,改變你對編碼的認知

以下是數獨解算器的運行結果:

6 個新奇的編程方式,改變你對編碼的認知

不幸的是,聲明式編程語言很容易造成性能瓶頸。上面的排序算法很可能 O(n!)讓數獨解算器進行了一次強力搜索; 而且大多數開發人員必須提供數據庫提示和額外索引,避免執行SQL查詢時出現代價高昂且效率低下的情況。

符號編程

6 個新奇的編程方式,改變你對編碼的認知

示例語言:Aurora

Aurora語言是一個典型的符號編程的例子:它不僅包括純文本編程,而且還包括圖像,數學方程,圖形,圖表等。這能夠用該數據的原始格式操作和描述各種數據,而不是用文本描述所有數據。Aurora也是完全互動的,可以立即顯示每行代碼的結果,例如 REPL。

Aurora語言由Chris Granger創建,他也創建了Light Table IDE。Chris在他的文章中概述了Aurora的動機:實現更好的編程。目標是使編程更加具有可觀察性,直接並減少偶然的複雜性。欲瞭解更多信息,請務必查看Bret Victor令人難以置信的會談: Inventing on Principle, Media for Thinking the Unthinkable, and Learnable Programming。

基於知識的編程

6 個新奇的編程方式,改變你對編碼的認知

示例:Wolfram語言

像上面提到的 Aurora 語言一樣,Wolfram語言也是基於符號編程的。但是,符號層僅僅是為Wolfram語言的核心提供一致的接口的一種方式,這是基於知識的編程:內置於大量的庫,算法和數據。這使得從繪製Facebook連接到操縱圖像,查看天氣,處理自然語言查詢,繪製地圖上的方向,求解數學方程式等等都可以輕鬆地完成。

我懷疑 Wolfram 語言是否有最大的“標準庫”和有任何語言的數據集。互聯網的連接是編寫代碼的內在組成部分的想法讓我感到興奮:它幾乎就像一個自動完成功能進行谷歌搜索的IDE。符號編程模型是否像Wolfram聲稱的那樣靈活,而且可以真正利用所有這些數據?如果是的話,會很有趣。

更新:雖然Wolfram聲稱Wolfram語言支持“符號編程”和“知識編程”,但這些術語的定義略有不同。更多有關信息,請參閱知識編程和符號編程wiki。


分享到:


相關文章: