haskell - Haskell 中常见的 monad 对应的伴随仿函数对是什么?

标签 haskell category-theory

在范畴论中,单子(monad)可以由两个伴随仿函数构造而成。特别是,如果CD是类别,并且F : C --> DG : D --> C 是伴随仿函数,即存在双射

hom(FX,Y) = hom(X,GY)

对于C中的每个XD中的Y,则组合G o F: C --> C 是一个单子(monad)。

<小时/>

可以通过固定类型 b 并取 FG 来给出一对这样的伴随仿函数

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-sets 之间的双射是通过柯里化(Currying)给出的(模构造函数):

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)

我不知道这个 monad 的名字应该是什么,除了它似乎是一个类似阅读器 monad 的东西,它携带着一段可重写的信息(编辑: dbaupp 点在评论中指出这是 State monad。)

因此,State 单子(monad)可以“分解”为一对伴随仿函数 FG,我们可以这样写

State = G . F

到目前为止,一切顺利。

<小时/>

我现在正在尝试弄清楚如何将其他常见单子(monad)分解为成对的伴随仿函数 - 例如 Maybe[]Reader code>、WriterCont - 但我无法弄清楚我们可以将它们“分解”成的伴随仿函数对是什么。

唯一简单的情况似乎是Identity monad,它可以分解为任何一对仿函数FG,这样FG 相反(特别是,您可以只采用 F = IdentityG = Identity)。

有人可以透露一些信息吗?

最佳答案

您正在寻找的是 Kleisli category 。它最初的开发是为了表明每个单子(monad)都可以由两个伴随仿函数构建。

问题是 Haskell 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)

请注意,如果我们取 ->对于两者cd我们得到一个 Haskell 范畴的内仿函数,它就是 fmap 的类型。 :

cfmap :: (a -> b) -> (f a -> f b)

现在我们有了显式类型类,它表示两个给定类别之间的仿函数 cd我们可以表达给定单子(monad)的两个伴随仿函数。左边映射一个对象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反对m a并映射态射 gjoin . 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 中表达这一点的更好方法,请告诉我。)

关于haskell - Haskell 中常见的 monad 对应的伴随仿函数对是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13937289/

相关文章:

haskell - 从 "Real World Haskell?"实现 splitWith 的正确方法是什么

haskell - 嗨::(b -> c) -> (a -> b) -> (a -> c) 在 Haskell

haskell - 无法弄清楚这个单利函数需要什么类型签名

haskell - Functor 类型类背后的历史是什么?

haskell - 使 Applicative 成为 Monad 所需的 'minimum' 是什么?

haskell - 棱镜或仿射遍历的对偶是什么?

haskell - 有没有办法制作一个不使用持久ID机制的表键?

pdf - 在 Haskell 中将 .rtf 转换为 .pdf

haskell - 部分应用的中缀运算符的名称 "section"来自哪里?

haskell - 每个单子(monad)都是幺半群?