Haskell 中的 Algebraic data type
問題意識
如何根據現有的type組成新的type?有哪些組成方式?
讓我們先把 type 想成是 一組值的集合,舉例來說,正整數的type是從1開始一路往上加1的所有值所組成的一個集合;而
Bool
type則是由True
和False
這兩個值所組成的集合。我們現在問的問題是,要如何根據原有的type組出新的type,就好像是在問說,我們要怎麼根據現有的不同集合,去拼湊出一個新的集合。
兩種思路
1. and思維/組合/Product Type
使用 and,將兩種以上的type組合在一起。假設我們想為一本書的建模,那麼我們可以說一本書是由:
- 書名
- 作者
- 出版年份
- 頁數
- ISBN
所構成。物件導向語言中的Class,遵循的就是這樣的思路,把和一個類別相關連的所有屬性組織在一起。舉例來說,我們可以建立一個名為Book的類別,相對應的,這個Book class中具有:
- 書名屬性(字串)
- 作者屬性(字串)
- 出版年份屬性(正整數)
- 頁數屬性(正整數)
- ISBN屬性(正整數屬性)
透過上述這種利用並列組合的思考方式,稱為Product Type。
1 | # python程式碼範例 |
更多例子
- 一台電腦由CPU、記憶體、鍵盤、螢幕…等所組成
- 一個地址由郵遞區號、國家、縣市、路名、巷弄、號碼所組成
為什麼叫作Product type
Product type的名稱與集合論中的笛卡爾積(Cartesian Product)有關。
一個簡化的模型,
data ABC = ABC Bool Bool Bool
(True, False)
(False, True)
(True, True)
(False, False)
(待補)
2. or思維/並列/Sum Type
上面的and思維把焦點放在一個類型由哪些成分組合成在一起。但我們還有另一種看世界的方式:一個類型可以分別是哪些東西。舉個例子來說,我們可以根據男生、女生、其他這三種type,並列組合成性別
這個新的type。
我們來對比一下兩種說法:
- 一本書由[書名、作者、出版年、頁數]所組成
- 一個性別由[男生、女生、其他]所組成
表面上,這兩個句子都是以「…由…所組成」的句型,乍看之下好像是同一件事,但其實仔細去想一下後,就可以發現其中最大的差別:
- 一本書必須同時具有[書名、作者、出版年、頁數]
- 一個人的性別只能是[男生]或者[女生]或者[其他]其中之一
使用 or,例如 Bool
type 由 True 或 False 組成。。稱為Sum Type。
0與1
在乘法中,任何數a乘以1還是等於a自己。
a * 1 = a
在加法中,任何數a加上0還是等於a自己。
a + 0 = a
Void: 是一個不具有任何元素的type。
data Void
Void
是一個type constructorVoid
沒有data constructor,因為Void這個type不具有任何元素
1 | data X a = X a | Y Void |
Unit: 是一個只具有一個元素的type,以()
表示。
Unit
是一個type constructorUnit
只有一個元素:()
1 | type Y a = (a, ()) |
將Type與代數計算相關連
以代數中的加法與乘法來看資料結構:
代數
- Symbols: 0, 1, 2, …, x, y, z, ….
- Operations: +, -, *, /
- Laws: 結合律、分配律、0+x=x
Haskell
- Symbols: (), Int, Bool, …
- Operations: Type Constructors (Maybe, Either, [],…)
- Laws: ???
One
data Unit = Unit
data () = ()
type 為 Unit, 其 data constructor 沒有參數。只有一個值。
加法
data a:+ b = AddL a | AddR b
data Either a b = Left a | Right b
以Either Bool Bool
為例,一共有四個值:
- Left True
- Left False
- Right True
- Right False
因此可以作為加法的定義。
乘法
data a:* b = Mul a b
data (a, b) = (a, b)
以(Bool, Bool)
為例,一共有四個值:
- (T, T)
- (T, F)
- (F, T)
- (F, F)
tuple的第一個元素有T和F兩種選項,第二個元素也有T和F兩種選項,所以(Bool, Bool)
會有 2 * 2 = 4 種可能。
Zero
data Void
Void
是一個含有0個值的type。
Two
type Two = Unit :+ Unit
data Bool = True | False
Function
data a -> b
a->b <=> b^ a
因此可以作為加法的定義。
數學 | Haskell | |
---|---|---|
Symbols\n東西 | ||
Operations | ||
Laws |