學習 Clojure/函數語言程式設計
函數語言程式設計是程式設計中那些不幸的術語之一,它籠罩在濫用和混亂中,但實際上並不應該那麼神秘。最適合理解為指令式程式設計的另一種正規化,函數語言程式設計的特點是
- 無副作用函式
術語“函式式”來自數學,在數學中,函式嚴格地只根據零個或多個輸入值返回值,並且不產生副作用,也不根據除傳遞給它的值以外的任何值更改其行為。這樣的“純”函式在每次使用相同的值集呼叫時都返回相同的東西。
這與命令式(非函式式)程式設計中函式的工作方式不同。在命令式程式碼中,函式通常
- 產生副作用(例如寫入檔案或某個 I/O 裝置)
- 修改其輸入和全域性變數
- 根據函式之外的狀態更改其行為
純函式有兩個主要優點
- 避免修改本地資料並避免讀取或修改全域性資料的函式更容易理解,並且更適合正確性證明。
- 避免讀取和寫入共享狀態的函式可以在沒有併發性通常的擔憂的情況下併發執行。
現在,對編寫所有函式以在沒有副作用的情況下執行的明顯反對意見是,我們需要副作用才能使我們的程式最終執行任何有用的操作。正如諺語所說,沒有副作用的程式只會讓你的 CPU 變熱。因此,函數語言程式設計中的理想目標只是隔離狀態更改,而不是完全消除它們。在像 Haskell 這樣的純函式式語言中,函式純度由編譯器強制執行,這樣所有潛在的副作用都必須在程式碼中明確地限定。但是,像 Clojure 這樣的不純函式式語言不會執行這種強制:Clojure 幫助你以函式式的方式構建程式碼,但最終取決於你來將副作用排除在你的純函式式程式碼之外。
- 不可變資料
如果函式要避免修改狀態,如果它們要避免依賴修改狀態,那麼將盡可能多的資料設為不可變是有意義的:如果資料不能更改,那麼它可能不會更改的危險就不存在。在 Clojure 中,標準集合型別是不可變的,實際上,即使區域性變數也是不可變的:一旦定義,繫結到區域性的值就不會改變。
你可能在想這會讓 Clojure 聽起來不可用,但令人驚訝的是,在沒有可變資料的情況下可以完成多少工作。確實,現實世界中的程式不能完全具有不可變的資料,但與只習慣指令式程式設計的程式設計師普遍認為的相比,可以使更多的資料變得不可變。
- 一等函式
在函數語言程式設計中,函式是“一等”,即函式本身是值,可以作為引數傳遞或儲存在變數中。許多動態語言——Javascript、Ruby、Python 等——都有一等函式,但這些語言通常不被認為是函式式語言。
- 基於函式的控制流
在命令式語言中,控制流是透過特殊結構實現的,例如if-else 語句。在函式式語言中,控制流機制要麼是函式,要麼至少是函式類似的,因為它們返回值。例如,Clojure 中的if 執行兩個分支之一,並返回該分支返回的值。這樣的結構允許使用否則需要修改變數的習語。