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 中,**這相當於有一對態射 fg,這樣:

 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 型別的類別,因此我們將只看到從 HaskHask 的仿函式,那些起源和目標類別相同的仿函式被稱為 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)。有關此主題的詳細討論,請參見此處