Haskell 型別作為一個類別
類別的定義
Haskell 型別以及型別之間的函式形成(幾乎†)類別。我們對每個物件(型別)a
都有一個身份態射(函式)(id::a -> a
); 和態度((.) :: (b -> c) -> (a -> b) -> a -> c
)的組成,遵守範疇法:
f . id = f = id . f
h . (g . f) = (h . g) . f
我們通常將此類別稱為 Hask 。
同構
在範疇論中,當我們有一個具有逆的態射時,我們有一個同構,換句話說,有一個態射,它可以與它組成以產生同一性。在 **Hask 中,**這相當於有一對態射 f
,g
,這樣:
f . g == id == g . f
如果我們在兩種型別之間找到一對這樣的態射,我們稱它們彼此同構。
一些 a
的兩個同構型別的例子是 ((),a)
和 a
。我們可以構造兩個態射:
f :: ((),a) -> a
f ((),x) = x
g::a -> ((),a)
g x = ((),x)
我們可以檢查一下 f . g == id == g . f
。
函子
類別理論中的仿函式從一個類別到另一個類別,對映物件和態射。我們只處理一個類別, Hask of Haskell 型別的類別,因此我們將只看到從 Hask 到 Hask 的仿函式,那些起源和目標類別相同的仿函式被稱為 endofunctors 。我們的 endofunctors 將是一個型別並返回另一個型別的多型型別:
F :: * -> *
遵守分類函子定律(保留身份和構成)相當於遵守 Haskell 仿函式法則:
fmap (f . g) = (fmap f) . (fmap g)
fmap id = id
因此,我們有,例如,[]
,Maybe
或 (-> r)
是仿函式 Hask 。
單子
類別理論中的 monad 是 endofunctors 類別的 monoid 。這個類別有 endofunctors 作為物件 F :: * -> *
和自然變換(它們之間的轉換 forall a . F a -> G a
)作為態射。
monoid 物件可以在 monoidal 類別上定義,並且是具有兩個態射的型別:
zero :: () -> M
mappend :: (M,M) -> M
我們可以將其粗略地轉換為 Hask endofunctors 的類別:
return::a -> m a
join::m (m a) -> m a
並且,遵守 monad 法則相當於遵守分類的 monoid 物件定律。
†事實上,由於 undefined
的存在,所有型別的類以及型別之間的函式類並不嚴格地形成 Haskell 中的類別。通常,這可以通過簡單地將 Hask 類別的物件定義為沒有底值的型別來解決,這排除了非終止函式和無限值(codata)。有關此主題的詳細討論,請參見此處 。