函數式編程的興衰與當前之崛起

本文做者: Eric Elliott

編譯:鬍子大哈 javascript

翻譯原文:huziketang.com/blog/posts/…

英文鏈接:The Rise and Fall and Rise of Functional Programming (Composing Software)前端

轉載請註明出處,保留原文連接以及做者信息java

本文是「組合式軟件」系列的一篇文章,從頭開始學習函數式編程和使用 JavaScript ES6+ 進行軟件編程。請繼續關注,後面還有不少相關內容。react

在我 6 歲的時候,我天天花不少時間和我最好的朋友一塊兒打遊戲,他們家裏有不少電腦。對我來說它有種魔幻版不可抗拒的力量。有一天我忽然問我朋友:「咱們怎樣才能本身作一個遊戲呢?」編程

他也不知道,因此咱們一塊兒去問他的爸爸,叔叔從很高的架子上拿下來一本書:Basic。我也由此開始了個人編程之旅。後來大學都有代數這門課程,而我對它已經很熟悉了,由於編程裏面代數是基礎,處處都是代數。數組

組合式軟件的興起

在計算機科學剛剛起步的時候,不少計算機科學的理論都尚未落地。那時候有兩個偉大的計算機科學家:阿隆佐·丘奇和阿蘭·圖靈。他們創造了兩個不一樣的,可是具備同等效力的通用計算模型。兩個模型均可以計算任何能夠計算的東西(着重強調,「通用」)。瀏覽器

阿隆佐·丘奇發明了 λ 演算, λ 演算是基於函數應用的通用計算模型。阿蘭·圖靈則因圖靈機而廣爲人知。圖靈機定義了一個理論上的設備,它能夠控制條帶上的符號。他們合做證實了 λ 演算和圖靈機是功能等價的。架構

λ 演算所有都是關於函數組合。函數組合在軟件開發中是很是富有表現力和說服力的。本文中,咱們會討論函數組合在軟件設計中的重要性。app

這裏有三點關於 λ 演算的特殊說明:編程語言

  1. 函數一般是匿名的。在 JavaScript 中,const sum = (x, y) => x + y 的右邊是匿名函數,即 (x, y) => x + y
  2. λ 演算中的函數只接受單一輸入,它是一元的。若是你須要傳遞多參數,函數會接受第一個輸入而且返回一個新的函數來接受第二個參數,以此類推。一個 n 元函數 (x, y) => x + y 能夠表達爲一個一元函數:x => y => x + y。這種 n 元函數到一元函數的轉化叫作柯里化。
  3. 函數是一級的。意思是說一個函數能夠做爲另外一個函數的輸入,而且一個函數能夠返回另外一個函數。

這些特徵一塊兒構成了簡單且容易理解的規則,在組合式軟件中使用函數做爲主要編碼單元。在 JavaScript 中,匿名函數和柯里化函數都是可選特徵,也就是說 JavaScript 支持 λ 演算的主要特徵可是並不強制使用。

經典的函數組合是把一個函數的輸出做爲另外一個函數的輸入,例以下面的組合:

f·g複製代碼

能夠寫成:

compose2 = f => g => x => f(g(x))複製代碼

下面是如何使用它:

double = n => n * 2
    inc = n => n + 1
    compose2(double)(inc)(3)複製代碼

compose2() 函數接受 double 函數做爲第一個參數,inc 函數做爲第二個參數,最後應用參數 3 到這兩個函數組合上。再看一下 compose2() 的聲明,fdouble()ginc()x3。函數調用 compose2(double)(inc)(3),其實是三個不一樣的函數調用:

  1. 首先傳遞 double 返回一個新函數 1;
  2. 新函數 1 以 inc 爲參數而且返回一個新函數 2;
  3. 新函數 2 以 3 爲參數而且計算 f(g(x)),即 double(inc(3))
  4. x=3 傳遞給 inc()
  5. inc(3) 計算結果是 4;
  6. double(4) 計算結果是 8
  7. 最終返回結果是 8

組合式軟件的過程能夠用函數組合圖來表達,看下面代碼:

append = s1 => s2 => s1 + s2
    append('Hello, ')('world!')複製代碼

能夠用圖來模擬表示:

λ 演算對軟件設計的影響是深遠的,直到大約 1980 年,計算機科學界不少有影響力的品牌,都是採用函數組合的方式來開發本身的軟件。Lisp 是 1958 年發明的,它深受 λ 演算的影響。直到今天,Lisp 是依舊廣爲使用的第二大歷史悠久的語言。

我是經過 AutoLISP 知道的 Lisp,AutoLISP 是在最流行的電腦輔助設計(CAD)軟件——AutoCAD,中使用的腳本語言。AutoCAD 太流行了,使得其餘全部的 CAD 應用幾乎都支持 AutoLISP 以保持其兼容性。Lisp 依然可以在計算機科學課程中廣爲使用有三個主要緣由:

  1. Lisp 很是簡單,基本上能夠在一天以內學習完它的基本語法和語義;
  2. Lisp 基本上所有是函數組合,函數組合來作應用架構的方式很是優雅;
  3. 我所知道的最好的計算機科學課本使用Lisp:計算機程序的結構和解釋

組合式軟件的沒落

在 1970 到 1980 年期間,軟件開發的方式開始發生變化,簡單的組合式開發再也不受寵。出現了面向對象編程,它基於組件封裝和信息傳遞的思想,在當時是很是先進的。代碼經過繼承來實現複用,繼承關係是一種叫作 is-a 的關係。

函數式編程逐漸被邊緣化,被拋棄到學術界和非主流的場外。在 1990 — 2010 年期間對三種人造成了甜蜜的困擾,一種是編程極客,一種是大學教授,一種是逃離了 Java 思想強制灌輸的幸運的學生。而對於咱們來說,這 30 年的軟件開發有一點噩夢般的感受,黑暗的年代。

組合式編程的從新崛起

2010 年左右,有個巨大的變化:JavaScript 爆發了。在 2006 年之前,JavaScript 一直被認爲是一種玩具式的編程語言,能夠在瀏覽器中作一些很可愛的動畫,可是在這背後隱藏着潛力巨大的特色,即 λ 演算的重要特徵。人們開始逐漸在私下裏談論「函數式編程」。

到 2015 年,用函數組合來開發軟件從新開始流行起來。爲了簡化使用,JavaScript 規範也作了 10 年以來的首次重大升級,增長了箭頭函數。箭頭函數使建立和使用函數、柯里化和 λ 演算變得很容易。

箭頭函數對於 JavaScript 函數式編程的爆發起到了推進劑的做用。如今不多看到那種不用函數式編程的大型應用了。

組合的方式能夠簡潔清晰地描述軟件的行爲,把一些小的、肯定性的函數組合成大的組件,進而造成軟件,這樣的軟件很容易組織、理解、調試、擴展、測試和維護。

在讀接下來文章的時候,但願你能經過例子本身動手作實驗。回想一下當本身仍是的孩子的時候,把一些東西拆開,本身再學着組裝、拼接。從新找回童年探索事物的感受,但願你能享受這個過程。

若是本文對你有幫助,歡迎關注個人專欄-前端大哈,按期發佈高質量前端文章。


我最近正在寫一本《React.js 小書》,對 React.js 感興趣的童鞋,歡迎指點

相關文章
相關標籤/搜索