Monads作为附件
我一直在阅读有关monad的分类理论。 单子的一个定义使用一对伴随函数。 monad通过使用这些函子的往返来定义。 显然助理在类别理论中非常重要,但我从来没有在伴随函数方面看到任何Haskell单子的解释。 有没有人给过它一个想法?
编辑 :只是为了好玩,我会正确地做到这一点。 原始答案保存在下面
现在,类别附加组件的当前附加代码位于附件包中:http://hackage.haskell.org/package/adjunctions
我只是明确而简单地通过状态monad。 此代码使用来自变压器包的Data.Functor.Compose
,但是它是自包含的。
f(D→C)和g(C→D)之间的一个连接点写成f - | g,可以用多种方法表征。 我们将使用counte / unit(epsilon / eta)描述,它给出了两个自然变换(仿函数之间的态射)。
class (Functor f, Functor g) => Adjoint f g where
counit :: f (g a) -> a
unit :: a -> g (f a)
请注意,议会中的“a”实际上是C中的身份函子,单位中的“a”实际上是D中的身份函子。
我们也可以从coun / unit定义中恢复hom-set的附属定义。
phiLeft :: Adjoint f g => (f a -> b) -> (a -> g b)
phiLeft f = fmap f . unit
phiRight :: Adjoint f g => (a -> g b) -> (f a -> b)
phiRight f = counit . fmap f
无论如何,我们现在可以从我们的单位/议会联盟中定义Monad,如下所示:
instance Adjoint f g => Monad (Compose g f) where
return x = Compose $ unit x
x >>= f = Compose . fmap counit . getCompose $ fmap (getCompose . f) x
现在我们可以实现(a,)和(a - >)之间的经典连接:
instance Adjoint ((,) a) ((->) a) where
-- counit :: (a,a -> b) -> b
counit (x, f) = f x
-- unit :: b -> (a -> (a,b))
unit x = y -> (y, x)
现在是一个类型的同义词
type State s = Compose ((->) s) ((,) s)
如果我们用ghci加载它,我们可以确认这个状态正是我们经典的状态monad。 请注意,我们可以采取相反的构图,并获得Costate Comonad(又名商店comonad)。
我们可以用这种方式将其他一些附加元素制作成monad(比如(Bool,Pair)),但它们有点奇怪。 不幸的是,我们无法以愉快的方式直接在Haskell中引发Reader和Writer。 我们可以做Cont,但是正如copumpkin所描述的那样,它需要来自相反类别的一个连接,所以它实际上使用了“Adjoint”类型类型的一个不同的“形式”,以反转一些箭头。 这种形式也在辅助包中的不同模块中实现。
Derek Elkins的文章“Monad Reader 13 - 用分类理论计算Monad:http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf”中的文章以不同的方式介绍了此材料。
此外,Hinze最近的Kan扩展程序优化论文从Mon
和Set
之间的连接中逐步构建了list monad:http://www.cs.ox.ac.uk/ralf.hinze/Kan.pdf
老答案:
两个参考。
1)类别附加服务像往常一样提供辅助表示,以及monad如何从中产生。 像往常一样,用文件思考是很好的,但很重要:http://hackage.haskell.org/packages/archive/category-extras/0.53.5/doc/html/Control-Functor-Adjunction.html
2)-Cafe还提供了一个有前途但简短的讨论副作用的讨论。 其中一些可能有助于解释类别附加说明:http://www.haskell.org/pipermail/haskell-cafe/2007-December/036328.html
Derek Elkins最近在晚餐中向我展示了Cont Monad如何由自己构造(_ -> k)
逆变函子而产生,因为它恰好是自伴随的。 这就是你从(a -> k) -> k
中得到的。 然而,它的议会导致双重否定消除,这在Haskell中是不能写的。
有关说明和证明这一点的一些Agda代码,请参阅http://hpaste.org/68257。
这是一个古老的线索,但我发现这个问题很有趣,所以我自己做了一些计算。 希望巴托斯仍然在那里,可能会读这..
事实上,Eilenberg-Moore建筑在这种情况下确实给出了非常清晰的图像。 (我将使用带有Haskell语法的CWM符号)
假设T
是列表monad < T,eta,mu >
( eta = return
和mu = concat
),并考虑T代数h:T a -> a
。
(请注意, T a = [a]
是一个自由幺半群<[a],[],(++)>
,即identity []
和multiplication (++)
。)
根据定义, h
必须满足hT h == h.mu a
和h.eta a== id
。
现在,一些简单的追图证明了h
实际上在(由x*y = h[x,y]
定义的)上诱导出一个幺半群结构,并且h
成为这个结构的幺半群同态。
相反,在Haskell中定义的任何幺半群结构< a,a0,* >
自然被定义为T代数。
通过这种方式( h = foldr ( * ) a0
,这个函数用(*)
'替换' (:)
并将[]
映射到a0
)。
因此,在这种情况下,T代数的范畴只是Haskell,HaskMon中可定义的幺半群结构范畴。
(请检查T-algebras中的态射实际上是幺半同态。)
它还将HasksMon中的列表表示为通用对象,就像Grp中的免费产品,CRng中的多项式环等一样。
对应于上述结构的辅助是< F,G,eta,epsilon >
哪里
F:Hask -> HaskMon
,其类型为' a
'生成的自由monoid,即[a]
, G:HaskMon -> Hask
,健忘函数(忘记乘法), eta:1 -> GF
,由x::a -> [x]
定义的自然转换, epsilon: FG -> 1
,由上面折叠函数定义的自然变换(从一个自由幺半群到它的商幺半群的'正则投影') 接下来,还有另一个'Kleisli类别'和相应的附件。 您可以检查它是否只是具有态射a -> T b
的Haskell类型的类别,其组成由所谓的'Kleisli组合' (>=>)
。 一个典型的Haskell程序员会发现这个类别更熟悉。
最后,正如CWM所示,T-代数的范畴(或Kleisli范畴)在合适的意义上成为定义列表单子T的范畴中的终端(或初始)对象。
我建议为二叉树函子T a = L a | B (T a) (T a)
做一个类似的计算 T a = L a | B (T a) (T a)
检查你的理解。
下一篇: Java: using a RuntimeException to escape from a Visitor