What are the adjoint functor pairs corresponding to common monads in Haskell?

后端 未结 3 1572
半阙折子戏
半阙折子戏 2021-01-30 09:14

In category theory, a monad can be constructed from two adjoint functors. In particular, if C and D are categories and F : C --> D and G : D -->

相关标签:
3条回答
  • 2021-01-30 09:31
    • Maybe comes from the free functor into the category of pointed sets and the forgetful functor back
    • [] comes from the free functor into the category of monoids and the forgetful functor back

    But neither of these categories are subcategories of Hask.

    0 讨论(0)
  • 2021-01-30 09:37

    What you're looking for is Kleisli category. It was originally developed to show that every monad can be constructed from two adjoint functors.

    The problem is that Haskell Functor is not a generic functor, it's an endo-functor in the Haskell category. So we need something different (AFAIK) to represent functors between other categories:

    {-# 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)
    

    Notice that if we take -> for both c and d we get an endo-functor of the Haskell category, which is just the type of fmap:

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

    Now we have explicit type class that represents functors between two given categories c and d and we can express the two adjoint functors for a given monad. The left one maps an object a to just a and maps a morphism f to (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
    

    The right one maps an object a to object m a and maps a morphism g to join . liftM g, or equivalently to (=<<) 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
    

    (If anybody know a better way how to express this in Haskell, please let me know.)

    0 讨论(0)
  • 2021-01-30 09:49

    As you observe, every pair of adjoint functors gives rise to a monad. The converse holds too: every monad arises in that way. In fact, it does so in two canonical ways. One is the Kleisli construction Petr describes; the other is the Eilenberg-Moore construction. Indeed, Kleisli is the initial such way and E-M the terminal one, in a suitable category of pairs of adjoint functors. They were discovered independently in 1965. If you want the details, I highly recommend the Catsters videos.

    0 讨论(0)
提交回复
热议问题