問題意識

如何根據現有的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

參考資料

留言與分享

Haskell

分類 Haskell

使用data宣告全新的type

與type declaration只是宣告一個「關於既存類型的同義詞」不同,使用data關鍵字可以宣告全新的類型。
在Prelude中,Bool類型即是以下列方式宣告的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
data Bool = True | False
```
- 在``=``左邊的稱為 type constructor (上例中的``Bool``)
- 在``=``右邊的稱為 data constructor 或 value constructor (上例中的``True`` 或 ``False``)


## 使用 type parameter 的時機

> We usually use type parameters when the type that's contained inside the data type's various value constructors isn't really that important for the type to work

f

> 名詞定義:
> concrete types, fully applied type: 像是 ``Maybe Int``, ``Maybe Char``
> 至於``Maybe``本身只是一個**type constructor**,並非具體的type。任何值都必須具有concrete type。
> 比較 ``Maybe`` 和 ``Maybe Int``:``Maybe``是一個type constructor,``Maybe Int``則是一個 concrete type

## 好好區分 type constructor 和 data constructor
type constructor只能出現在下面用``...``表示的幾個地方:

- ``data ... =``
- ``type ... =``
- ``::...``
- ``instance Eq ... where``

# 使用``type``為現存的type宣告新的別名

稱為 type synonym。用來給一個既有type提供一個別名。什麼時候需要這樣大費周章為已經存在的type提供新的名稱?

> We introduce type synonyms either to describe what some existing type represents in our functions (and thus our type declarations become better documentation) or when something has a long-ish type that's repeated a lot (like ``[(String,String)]``) but represents something more specific in the context of our functions.
> [LYAH](http://learnyouahaskell.com/making-our-own-types-and-typeclasses)

``Char``是一個Haskell本身就定義好的type,如果要以``Char``為基礎,建立新的type,那麼就要使用``type``:

type String = [Char]

1
2

``Int``也是一個Haskell本身就有的、用以表達整數的type,如果想建立一個正整數座標的Point type,並包在tuple中,可以使用:

type Point = (Int, Int)

1
2
3
4

當然,定義好新的type之後,新的type就可以用在別的type宣告中。

也許有一系列的function都與「將一個Point轉換到另一個Point」有關,因此可以為這群函數宣告一個新的type:

type Transformation = Point -> Point

1
2

## Type synonym也可以具有type parameters

type Pair a = (a, a)
`
一個Pair可以是Pair Int (Int, Int),可能是(Char, Char)

參考資料

留言與分享

  • 第 1 頁 共 1 頁
作者的圖片

puerdon

學習筆記 / 資源整理 / 雜物堆放


語言學研究