Are there contravariant monads?

前端 未结 2 1858
后悔当初
后悔当初 2020-12-15 18:03

Functors can be covariant and contravariant. Can this covariant/contravariant duality also be applied to monads?

Something like:

class Monad m where
         


        
2条回答
  •  伪装坚强ぢ
    2020-12-15 18:45

    A contravariant functor is a functor from one category into its opposite category, i.e. from one category into another (albeit closely related) one. OTOH, a monad is foremostly an endofunctor i.e. from one category into itself. So it can't be contravariant.

    This kind of stuff always tends to be a lot clearer when you consider the “fundamental mathematical” definition of monads:

    class Functor m => Monad m where
      pure :: a -> m a
      join :: m (m a) -> m a
    

    As you see there aren't really any arrows in there that you could turn around in the result, like you did with contrabind. Of course there is

    class Functor n => Comonad n where
      extract :: n a -> a
      duplicate :: n a -> n (n a)
    

    but comonads are still covariant functors.

    Unlike monads, applicatives (monoidal functors) needn't be endofunctors, so I believe these can be turned around. Let's start from the “fundamental” definition:

    class Functor f => Monoidal f where
      pureUnit :: () -> f ()
      fzipWith :: ((a,b)->c) -> (f a, f b)->f c  -- I avoid currying to make it clear what the arrows are.
    

    (exercise: define a derived Applicative instance in terms of this, and vice versa)

    Turning it around

    class Contravariant f => ContraApp f where
      pureDisunit :: f () -> ()
      fcontraunzip :: ((a,b)->c) -> f c->(f a, f b)
                                -- I'm not sure, maybe this should
                                -- be `f c -> Either (f a) (f b)` instead.
    

    No idea how useful that would be. pureDisunit is certainly not useful, because its only implementation is always const ().

    Let's try writing the obvious instance:

    newtype Opp a b = Opp { getOpp :: b -> a }
    
    instance Contravariant (Opp a) where
      contramap f (Opp g) = Opp $ g . f
    
    instance ContraApp (Opp a) where
      pureDisunit = const ()
      fcontraunzip z (Opp g)
         = (Opp $ \a -> ???, Opp $ \b -> ???) -- `z` needs both `a` and `b`, can't get it!
    

    I don't think this is useful, though you might be able to define it with something like clever knot-tying recursion.

    What might be more interesting is a contravariant co-monoidal functor, but this gets too weird for me right now.

提交回复
热议问题