剛接觸 FP 時,Immutable 是讓我最不可思議的概念,Variable 天生就是拿來給人修改的,但 FP 卻教人 Immutable 不可修改,這是什麼奇怪思想呢 ?
Version
macOS Catalina 10.15.2
VS Code 1.40.2
Quokka 1.0.259
ECMAScript 2015
Mutable
const arr = [1, 2, 3]
arr[0] = 4
arr // ?
ECMAScript 的 primitive 是 immutable,儘管 array 、object 使用了 const
宣告,只是不能 re-assign 而已,依然是 mutable。
也就是嚴格來說,ECMAScript 對於 immutable 支援仍未達 FP 標準。
Immutable
回到更基本問題,為什麼需要 immutable 呢 ?
由於 ECMAScript 是 mutable,回想過去經驗,ECMAScript 最令人詬病有三點:
- 由於 variable 是 mutable,因此常會共用 variable,無論是 global variable,或者是 class 內的 private field,這些雖然使用方便,但由於其他 method 都可修改,卻也是 bug 來源
- 由於 variable 是 mutable,因此 method 內會伴隨著複雜的
if
判斷如何改變 variable,造成複雜度與維護困難 - 由於 variable 是 mutable,為了在該 scope 內修改 variable,而造成 method 越寫越大
FP 提出 immutable 概念,variable 只要建立之後就不可修改 !!
也因為不可修改,若結果要改變,只能將 variable 內容讀出,改變後再建立新的 variable,原來 variable 的內容依然不變。
若要由 2
變成 30
,中間過程須先經過 8
,然後 15
。
Mutable 會直接在同一個 variable 從 2
改成 8
,再改成 15
,最後再改成 30
,完全在同一個 variable 完成。
Immutable 由於 variable 不可修改,會另外建立新的 variable 放 8
,然後再建立新的 variable 放 15
,最後再建立新的 variable
放 30
,一共需要 4 個 variable。
也由於 immutable,由 2
變 8
,在由 8
變 15
,最後再由 15
變 30
,可發現原本 2
變 30
的任務,被切成 3 個小任務:
- 由
2
變8
- 由
8
變15
- 由
15
變30
而這 3 個小任務剛好就是數學的 y = f(x)
,也由於 y
的結果只跟 x
有關,因此也稱為 pure function。
而在眾多的小任務中,若發現流程有重複性,可再抽出 higher-order function,只傳入不重複部分即可。
最後可再將 pure function 與 higher-order function 透過 function composition 組合成單一 function。
由於 variable 為 immutable,因此不會再出現共用變數所導致的 bug
由於 variable 為 immutable,因此不再使用複雜的
if
判斷如何改變 variable也由於大任務被切割成小任務,因此每個 pure function 都很單純都很小,不會再出現大 method
Conclusion
- 若使用 mutable,除非個人功力極高,否則很難寫出 pure function、higher-order function 與 function composition 架構
- Immutable 可以算是 pure function 、higher-order function 與 function composition 的催化劑,由於 immutable 無法修改 variable,我們被逼的將修改 variable 的任務切割成眾多小任務而造就 pure function,在重構階段發現重複而抽出 higher-order function,最後再以 function composition 收工