函數式編程(一)

什麼是函數式編程

函數式編程是一種編程範式,常見的編程範式有以下三種:

  • 命令式編程
  • 聲明式編程
  • 函數式編程

函數式編程的本質是將計算描述爲一種表達式求值。在函數式編程中,函數作爲一等公民,可以在任何地方定義(在函數內或函數外),可以作爲函數的參數和返回值,可以對函數進行組合。

函數式編程的準則:不依賴於外部的數據,而且也不改變外部數據的值,而是返回一個新的值給你。看個簡單的例子:

    // 非函數式的例子
    let count = 0;
    function increment() {
        count++; // 依賴於函數外部的值,並改變了它的值
    }
    
    // 函數式的例子
    function increment(count) {
        return count++;
    }

爲什麼採用函數式編程

函數式編程不依賴外部的狀態也不修改外部的狀態,函數調用的結果不依賴調用的時間和位置,這些寫代碼容易進行推理,不易犯錯,而且單測和調試都更簡單。即函數編程採用純函數。

純函數是這樣一種函數,即相同的輸入,永遠會得到相同的輸出,而且沒有任何可觀察的副作用。

副作用可能包含,但不限於:

  • 更改文件系統
  • 往數據庫插入記錄
  • 發送一個 http 請求
  • 可變數據
  • 打印/log
  • 獲取用戶輸入
  • DOM 查詢
  • 訪問系統狀態
副作用是在計算結果的過程中,系統狀態的一種變化,或者與外部世界進行的可觀察的交互。

純函數的好處:

純函數能根據輸入來做緩存(memoize技術)

    const memoize = function(f) {
        const cache = {};
        return function() {
            const argStr = JSON.stringify(arguments);
            
            if (!cache[argStr]) {
                cache[argStr] = f.apply(f, arguments);
            }
            
            return cache[argStr];
        }
    }

可移植性/自文檔化
純函數的輸出只依賴與它的輸入,依賴很明確,易於理解。由於純函數不依賴它的上下文環境,因此我們可以輕易的把它移植到任何地方運行它。

可測試性
我們不必在每次測試前都去配置和構造初始環境,只需簡單給函數一個輸入,然後斷言它的輸出就好了。

合理性
由於純函數總是能夠根據相同的輸入返回相同的輸出,所以它們就能夠保證總是返回同一個結果,這也就保證了引用透明性。

並行執行
我們可以並行運行任意純函數。因爲純函數根本不需要訪問共享的內存,而且根據其定義,純函數也不會因副作用而進入競爭態。
並行代碼在服務端 js 環境以及使用了 web worker 的瀏覽器那裏是非常容易實現的,因爲它們使用了線程(thread)。不過出於對非純函數複雜度的考慮,當前主流觀點還是避免使用這種並行。

實現函數式編程的技術

這裏我們先不展開這些技術的細節內容,本文我們先側重於對函數式編程有一個整體上的認識,具體的技術細節我們將在下一章展開。

  • curry(柯里化)
  • compose(代碼組合)
  • Monad(Monad就是一種設計模式,表示將一個運算過程,通過函數拆解成互相連接的多個步驟。你只要提供下一步運算所需的函數,整個運算就會自動進行下去。)

如何正確看待函數式編程

我們先來看以下幾種觀點:

  • 你這段代碼用了 for 循環,這是過程式的。爲了優雅,你應該寫成函數式的。
  • 你這段代碼有副作用,這是骯髒的。爲了純淨性,你應該把 IO 包在 Monad 裏。
  • 你這段代碼用了 class,這是面向對象的。爲了無狀態,你應該寫成高階函數。

我想說的是這種偏激的觀點是不正確的,我們不應該把函數式編程和命令式編程對立起來,我們更多的時候需要考慮的是技術的適用場景。函數式編程寫起代碼來,有一定的難度,如果一個團隊的整體水平達不到,那麼寫代碼的質量和效率還不如採用命令式編程好。函數式編程利用純函數的無狀態性,它的好處非常多(結果可預期、利於測試、利於複用、利於併發),但一個系統工程的代碼,是不可能全部採用純函數來寫的。當我們越貼近業務,我們就離純函數與無狀態越遠。

函數式編程非常重要,學習它我們能打開我們的思維方式,使用它也有很多好處,但它也有一些侷限,我們應該客觀看待。保持開放的心態,根據實際場景選擇合適的技術,是一個工程師基本的素養。

參考資料

https://llh911001.gitbooks.io...
http://www.ruanyifeng.com/blo...
https://coolshell.cn/articles...
https://www.zhihu.com/questio...
https://zhuanlan.zhihu.com/p/...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章