Haskell中与公共单子对应的伴随函子对是什么?
在范畴论中,一个单子可以由两个伴随函子构成。特别是,如果C和D是类别,而F:C-->D和G:D-->C是伴随函子,则在存在双射的意义上 hom(FX,Y)=hom(X,GY) 对于C中的每个X和D中的每个Y,组合gof:C-->C是一个单子Haskell中与公共单子对应的伴随函子对是什么?,haskell,category-theory,Haskell,Category Theory,在范畴论中,一个单子可以由两个伴随函子构成。特别是,如果C和D是类别,而F:C-->D和G:D-->C是伴随函子,则在存在双射的意义上 hom(FX,Y)=hom(X,GY) 对于C中的每个X和D中的每个Y,组合gof:C-->C是一个单子 通过固定类型b并将F和G取为 data F b a = F (a,b) data G b a = G (b -> a) instance Functor (F b) where fmap f (F (a,b)) = F (f a, b) in
通过固定类型
b
并将F
和G
取为
data F b a = F (a,b)
data G b a = G (b -> a)
instance Functor (F b) where
fmap f (F (a,b)) = F (f a, b)
instance Functor (G b) where
fmap f (G g) = G (f . g)
hom集之间的双射通过下列公式给出(模构造函数):
iso1 :: (F b a -> c) -> a -> G b c
iso1 f = \a -> G $ \b -> f (F (a,b))
iso2 :: (a -> G b c) -> F b a -> c
iso2 g = \(F (a,b)) -> let (G g') = g a in g' b
在这种情况下,对应的monad是
data M b a = M { unM :: b -> (a,b) }
instance Monad (M b) where
return a = M (\b -> (a,b))
(M f) >>= g = M (\r -> let (a,r') = f r in unM (g r') a)
我不知道这个单子的名字应该是什么,除了它看起来像一个读卡器单子,它携带了一段可写的信息(edit:dbaupp在评论中指出这是状态
monad)
因此,状态
单子可以“分解”为一对伴随函子F
和G
,我们可以编写
State = G . F
到目前为止,一切顺利
我现在正试图找出如何将其他常见的单子分解成成对的伴随函子-例如,
也许
,[]
,读取器
,编写器
,Cont
-但我无法找出我们可以将它们“分解”成的成对伴随函子
唯一简单的情况似乎是Identity
单子,它可以分解为任何一对函子F
和G
,这样F
与G
是相反的(特别是,你可以取F=Identity
和G=Identity
)
有人能解释一下吗?你要找的是。它最初是为了证明每个单子都可以由两个伴随函子构成 问题是Haskell
函子
不是泛型函子,而是Haskell范畴中的内函子。因此,我们需要一些不同的(AFAIK)来表示其他类别之间的函子:
{-# LANGUAGE FunctionalDependencies, KindSignatures #-}
import Control.Arrow
import Control.Category hiding ((.))
import qualified Control.Category as C
import Control.Monad
class (Category c, Category d) => CFunctor f c d | f -> c d where
cfmap :: c a b -> d (f a) (f b)
请注意,如果我们对c
和d
都使用->
,我们会得到一个Haskell类的内函子,它就是fmap
的类型:
cfmap :: (a -> b) -> (f a -> f b)
现在我们有了显式类型类,它表示两个给定类别c
和d
之间的函子,我们可以表示给定单子的两个伴随函子。左图将对象a
映射到justa
,并将变形f
映射到(return.)f
:
-- m is phantom, hence the explicit kind is required
newtype LeftAdj (m :: * -> *) a = LeftAdj { unLeftAdj :: a }
instance Monad m => CFunctor (LeftAdj m) (->) (Kleisli m) where
cfmap f = Kleisli $ liftM LeftAdj . return . f . unLeftAdj
-- we could also express it as liftM LeftAdj . (return .) f . unLeftAdj
右边的一个将一个对象a
映射到对象ma
,并将一个态射g
映射到连接。liftM g
,或等效于(=),其中
cfmap(Kleisli g)=右调整。参加liftM g。不公正的
--这可以缩短为rightaj。(=
可能
来自自由函子,属于点集范畴,而健忘函子又回到了点集范畴
[]
来自自由函子,属于幺半群的范畴,而健忘函子又回来了
但这两个范畴都不是哈斯克的子范畴。正如你所观察到的,每对伴随函子都会产生一个单子。反之亦然:每一个单子都是以这种方式产生的。事实上,它以两种规范的方式产生。一种是佩特描述的克莱斯利构造;另一种是艾伦伯格-摩尔构造。的确,克莱斯利s是最初的这种方式,E-M是最终的方式,在一对合适的伴随函子中。它们是在1965年独立发现的。如果你想知道细节,我强烈推荐。你构造的单子就是状态单子。啊,当然。我会把它添加到我的单子列表中“有几次我在没有意识到的情况下重新发明了一个著名的monad实例。“将一个单子分解为指定函子的组合并不是唯一的,事实上,对于任何一个单子,都有一个完整的此类分解类别。可能最有用的两种分解是终端分解和初始分解:右伴随是(1)单子代数范畴中的健忘函子(Eilenberg-Moore类别)和(2)单子的自由代数类别(Kleisli类别)。@Omar:这个类别叫什么?@Sebastien:我认为它没有一个完全标准化的名称,但如果你称它为“单子的附加类别”每个人都会知道你的意思。谢谢Tom。我已经完成了这两个函数的细节——现在,我想知道其他例子中对应的函子是什么。而contr
来自逆变函子opr:Hask^Op-->Hask本身的附加,opra=a->r。很确定这两个都是Eilenb感谢杰里米——有几个人向我推荐了猫咪,我真的应该去看看。艾伦伯格·摩尔为州立单子所做的附属品的F-| G是什么?
newtype RightAdj m a = RightAdj { unRightAdj :: m a }
instance Monad m => CFunctor (RightAdj m) (Kleisli m) (->) where
cfmap (Kleisli g) = RightAdj . join . liftM g . unRightAdj
-- this can be shortened as RightAdj . (=<<) g . unRightAdj