今天要講的是 pattern matching ,觀念上跟 Day01 講的 immutable 有一點點關係,但其實還是可以當作獨立的概念。
如果有寫過 ES6+ 的讀者,應該對於解構賦值(destructuring assignment)
不陌生,語法寫起來大約是這樣:
// a = 'foo', b = { b: 'bar', c: 'baz' }
const { a, ...b } = { a: 'foo', b: 'bar', c: 'baz' }
// first = 1, second = 2, rest = [3, 4, 5]
const [first, second, ...rest] = [1, 2, 3, 4, 5]
解構賦值(destructuring assignment)
其實就隱含 pattern matching 的概念,就是如果等式的左邊跟右邊能找到一種方式能符合,則綁定 symbol & value。
但 pattern matching 的強大之處還不只如此,我們以 haskell 為例:
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
簡單說明一下語法:
fib :: Int -> Int
表示宣告一個 function 叫做 fib ,fib 會吃一個 Int 型態的參數而回傳 Int 型態的回傳值。
下面就是有趣的部分了。我們定義 fib 0 = 0
,fib 1 = 1
,意思就是說當參數是 0 時直接回傳 0,參數是 1 的時候直接回傳 1。附帶一提,在 haskell 裡括號是不必要的。
值得注意的部分有兩個:
fib 0 = 0
這段用賦值來解釋的話完全說不通,要怎麼賦值給一個函數呢?所以這段程式碼的解讀應為將 fib(0) 綁定到 0
,如果在 Day01 還沒抓到'='其實是綁定
這種感覺的讀者們可以感受一下這個概念。fib 0 = 0
的意義在於,如果我今天使用了fib n
而 n 恰巧 = 0,則(fib n) == (fib 0) == 0
,換言之 pattern matching 不只可以針對 symbol 做配對,甚至可以對值做配對!只要左右測的值符合綁定的條件(以此例來說, n == 0),是可以直接用值來配對的,這是大多數具備類似解構賦值
的特色的語言也做不到的。
pattern matching 搭配 guard,甚至可以在參數階段就做一些簡單的過濾,像是下列這段 Haskell 程式碼:
absolute x
| x < 0 = -x
| otherwise = x
意思是在 x < 0 時,函式的值 = -x,反之則為 x。不用用 if/else
就可以寫出簡單的判斷,這就是 pattern matching 的威力!
有興趣的讀者也可以參考這一篇等號究竟是什麼意思? Elixir 裡的 pattern matching,可以更深入了解 pattern matching 的機制。