近幾年有在寫前端的人,應該或多或少都有聽過 immutable 這個單字。
immutable,翻譯成中文就是不變的。不變聽起來不是什麼厲害的概念,以 C++ 來比喻就是 constant variable,早在 Functional Programming(下面稱 FP[1])風行好多年前就有這樣的特性了,有什麼特別之處呢?
神奇的地方在於,在(純) FP 的語言裡,所有的 symbol 都是 immutable 的。換言之,所謂變數的概念在(純) FP 的語言裡不存在,也因此本文不會使用變數(variable)來描述這個概念,而是使用 symbol[1]。任何的 symbol 在宣告的當下之後就不會再改變了,而事實上在 FP 語言裡也不存在賦值(assign)的概念,像在 Haskell 中 '=' 這個運算子意義是綁定(binding),a = 3
代表的意義是將 3 綁定給 a 這個 symbol
。
為什麼會有這種 everything is immutable 的概念呢?
對於語言是否支援 FP,有一個指標是在該語言中函數是否是一級公民(first class),也就是說可不可以讓函數被賦值到變數上,像 JavaScript 可以 let a = () => 3
,就是一個函數是一級公民的行為。但是在純 FP 中,不僅是把函數是一級公民而已,而是所有值都是函數,或可以視為函數。以前面一段所舉的 a = 3
這個例子來看,其實可以理解為 a 被綁定到一個沒有參數並永遠回傳常數 3 的函數
。
可以接受這個概念的話,就會發現:所謂的 FP 其實是指所有值都是函數,而綁定(binding)的過程只是把 symbol 指向函數,而不是儲存狀態。如果把每個 symbol 的值都想像成是函數,就可以比較理解為什麼 everything is immutable 了吧?就像整個程式碼裡面都只有函式宣告,自然就沒有所謂的變數了。
看完這一篇 stackoverflow或許可以稍微理解 FP 跟 OOP 的 immutable vs mutable 的差異。
既然狀態不能儲存在變數上,那要怎麼寫程式呢?總需要能儲存一些使用者輸入、開檔讀檔、HTTP request 等等各種 I/O 操作的結果才能寫出有用的程式吧?
很遺憾的,在這裏我還不會告訴你要怎麼做 I/O 操作與儲存狀態。事實上《Haskell 趣學指南》這本書直到第九章才教怎麼 I/O (其他語言第一課教的東西居然擺在第九章!),說不定後面的系列文有機會的話可以講到吧(不負責任)。
註[1]: 繁體中文翻成函式語言程式設計,但是感覺太長,所以這裏就用 FP
註[2]: symbol 也是很難翻成中文,乾脆用原文