在范畴论,一个单子可以从两个伴随函子来构建。 具体地,如果C和d是类和F:C - > d和G:d - > C是伴随函子,在这个意义上,有一个双射
坎(FX,Y)=坎(X,GY)
一种在C和Y各自X在d则组合物G.华氏度: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)
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
在这种情况下相应的单子是
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)
我不知道这个单子的名称应该是什么,但它似乎像一个读者单子,围绕一块过写信息( 编辑载:dbaupp在评论中指出,这是State
单子。)
因此, State
单子可以“分解”为一对伴随函子F
和G
,我们可以写
State = G . F
到现在为止还挺好。
现在,我试图找出如何分解等常见单子到伴随函子的对-例如Maybe
, []
Reader
, Writer
, Cont
-但我想不出什么对伴随函子的,我们可以“分解”他们进入ARE。
唯一的简单情况似乎是Identity
单子,它可以被分解成任何对函子F
和G
使得F
是逆G
(在尤其,可以只取F = Identity
和G = Identity
)。
任何人都可以提供一些线索?
什么你要找的是Kleisli类别 。 它最初被开发,以显示每一个单子可以从两个伴随函子来构建。
问题是,哈斯克尔Functor
不是一个通用的仿函数,它是一个内切算符,Haskell的类别。 因此,我们需要不同的东西(据我所知)代表其他类别之间的函子:
{-# 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
只是a
和射映射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
到join . liftM g
join . liftM g
,或等效于(=<<) 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
(如果有人知道一个更好的方式如何在Haskell来表达这一点,请让我知道。)
当你观察,每对伴随函子的产生了一个单子。 反过来也成立:每个单子以这种方式出现。 事实上,这样做有两种典型方式。 一个是Kleisli建设切赫介绍; 另一种是Eilenberg摩尔定律建设。 事实上,Kleisli是初始这样的方式和EM的终端之一,在对伴随函子的合适的类别。 他们在1965年各自独立发现如果你想的细节,我强烈推荐Catsters视频 。
文章来源: What are the adjoint functor pairs corresponding to common monads in Haskell?