说一说‘Monads’
1.关于范畴论
范畴论是数学的一门学科,以抽象的方法来处理数学概念,将这些概念形式化成一组组“物件”及“态射”。范畴论是对数学的某些分支的更高阶的抽象化,所以被称为“一般化的抽象废话”。
函子
将范畴再抽象一次(范畴自身也是数学结构的一种),寻找在某一意义下会保持其结构的过程,我们把这一过程称为函子,这实际上是定义了一个包含“范畴和函子”的范畴,元件为范畴,态射为函子。
一个从范畴 C 到范畴 D 的函子 F 被定义为:
- 对 C 中任意物件 X ,都有一个 D 中相应的物件 F(X) 与其对应;
- 对 C 中任意态射 f : X → Y ,都有一个 D 中相应的态射 F(f) : F(X) → F(Y) 与其对应;
并使下列性质成立:
- 对 C 中任意的物件 X ,都有 F(idX) = idF(X) 。
- 对 C 中任意两个态射 f : X → Y 和 g : Y → Z,都有 F(g · f) = F(g) · F(f) 。
将范畴映射到自身的函子被称为“自函子(Endofunctor)”。
组成
一个范畴‘C’是由三个部分组成:
1.一个类ob(C),里面的元素称为“物件”
2.一个类hom(C),其元素为“态射”或“箭号”。每个态射f 都只有一个“源物件”a 及一个“目标物件”b(其中a 和b 都在ob(C) 内),称之为“从a 至b 的态射”,标记为f : a → b。
3.一个二元运算,称为“态射复合”,使得对任意三个物件a、b 及c,都会有hom(b, c) × hom(a, b) → hom(a, c)。两个态射f : a → b 及g : b → c 的复合写做g ∘ f 或gf,并会符合下列两个公理:
- 结合律:若f : a → b、g : b → c及h : c → d,则h ∘ (g ∘ f) = (h ∘ g) ∘ f;
- 单位元:对任意物件x,总存在一个态射1x : x → x(称为x 的单位态射),使得对每个态射f : a → b,都会有1b ∘ f = f = f ∘ 1a。
(可以看出每个范畴只会有一个单位元,monad每个物件只会有一个单位态射)
2.Haskell与范畴论
Haskell中存在着这样的一种唯一的范畴Hask其满足我们上面所提到的范畴所满足的所有约定。
- 物件就是Haskell中的类型,注意Haskell中的类型是一个类,即是一个集合。
- 态射就是Haskell中的函数(function),如
f :: Int -> Bool
,函数f就是将Int这个物件的值映射到Bool物件的值上。 - 态射复合就是Haskell中函数的组合,比如
func = f.g
。
可以验证符合上面的两条公理。
由于Haskell中只有一个范畴,所以如果存在函子那么必然是映射到自身的自函子,那么Haskell中存不存在自函子呢?
首先要满足第一个条件:存在物件与物件之间的映射。在Haskell中,type constructor可以利用一个typeclass构造出其他的typeclass来,例如以下的定义:
Tree data Tree a = Tip | Node a (Tree a) (Tree a)
这里Node作为一类类型可以构造出Tree这种类型来。
第二个条件:态射与态射之间的映射。我们来看下面这种typeclass
class Functor f where fmap:: (a -> b) -> f a -> f b
typeclass fmap接受一个函数(物件与物件之间的映射),将其映射到另一个函数上(物件与物件的映射),所以说fmap是一个满足“态射与态射之间的映射”的一个typeclass。
3.monads
Monads是自函子范畴上的一个幺半群。