問題意識

如何根據現有的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
2
3
4
5
6
7
8
# python程式碼範例
class Book:
def __init__(self, title, author, year, pages, isbn):
self.title = title
self.author = author
self.year = year
self.pages = pages
self.isbn = isbn

更多例子

  • 一台電腦由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 constructor
Void沒有data constructor,因為Void這個type不具有任何元素

1
data X a = X a | Y Void

Unit: 是一個只具有一個元素的type,以()表示。

Unit是一個type constructor
Unit只有一個元素: ()

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

參考資料