定义“Monads 只是 endofunctors 类别中的幺半群。”,虽然这是一个糟糕的起点。它来自一篇博文,主要是为了开个玩笑。但是,如果您对通信感兴趣,可以在 Haskell 中进行演示:
范畴的外行描述是对象和对象之间态射的抽象集合。类别之间的映射称为函子,将对象映射到对象,将态射映射到态射关联并保留身份。内函子是从一个范畴到它自身的函子。
{-# LANGUAGE MultiParamTypeClasses,
ConstraintKinds,
FlexibleInstances,
FlexibleContexts #-}
class Category c where
id :: c x x
(.) :: c y z -> c x y -> c x z
class (Category c, Category d) => Functor c d t where
fmap :: c a b -> d (t a) (t b)
type Endofunctor c f = Functor c c f
满足所谓自然性条件的函子之间的映射称为自然变换。在 Haskell 中,这些是类型的多态函数:(Functor f, Functor g) => forall a. f a -> g a
.
一个范畴上的单子C
是三样东西(T,η,μ)
,T
是内函子和1
恒等函子C
。Mu 和 eta 是满足三角形恒等式和结合恒等式的两个自然变换,定义为:
在 Haskellμ
中是join
并且η
是return
return :: Monad m => a -> m a
join :: Monad m => m (m a) -> m a
Haskell 中 Monad 的分类定义可以写成:
class (Endofunctor c t) => Monad c t where
eta :: c a (t a)
mu :: c (t (t a)) (t a)
绑定运算符可以从这些派生。
(>>=) :: (Monad c t) => c a (t b) -> c (t a) (t b)
(>>=) f = mu . fmap f
这是一个完整的定义,但等效地,您也可以证明 Monad 定律可以表示为具有函子类别的 Monoid 定律。我们可以构造这个函子范畴,它是以对象为函子(即范畴之间的映射)和自然变换(即函子之间的映射)为态射的范畴。在一个内函子类别中,所有函子都是同一类别之间的函子。
newtype CatFunctor c t a b = CatFunctor (c (t a) (t b))
我们可以证明这产生了一个以函子组合作为态射组合的范畴:
-- Note needs UndecidableInstances to typecheck
instance (Endofunctor c t) => Category (CatFunctor c t) where
id = CatFunctor id
(CatFunctor g) . (CatFunctor f) = CatFunctor (g . f)
幺半群具有通常的定义:
class Monoid m where
unit :: m
mult :: m -> m -> m
一类函子上的幺半群具有作为恒等式 a 的自然变换和结合自然变换的乘法运算。可以定义 Kleisli 组合以满足乘法定律。
(<=<) :: (Monad c t) => c y (t z) -> c x (t y) -> c x (t z)
f <=< g = mu . fmap f . g
所以你有它“Monads 只是 endofunctors 类别中的幺半群”,这只是 endofunctors 和 (mu, eta) 的 monads 正常定义的“无点”版本。
instance (Monad c t) => Monoid (c a (t a)) where
unit = eta
mult = (<=<)
通过一些替换,我们可以证明(<=<)
Are 的等价语句的 monoidal 属性和单子自然变换的关联图。
f <=< unit == f
unit <=< f == f
f <=< (g <=< h) == (f <=< g) <=< h
如果您对图表表示感兴趣,我已经写了一些关于用字符串图表示它们的内容。