逆变函子是从一个类别到其opposite category 的函子,即从一个类别到另一个类别(尽管密切相关)。 OTOH,monad 主要是一个 endofunctor,即从一个类别到 itself。所以它不能是逆变的。
当您考虑 monad 的“基本数学”定义时,这类东西总是会变得更加清晰:
class Functor m => Monad m where
pure :: a -> m a
join :: m (m a) -> m a
正如您看到的那样,实际上并没有任何箭头可以在结果中翻转,就像您对contrabind 所做的那样。当然有
class Functor n => Comonad n where
extract :: n a -> a
duplicate :: n a -> n (n a)
但共单子仍然是协变函子。
与 monads 不同,applicatives (monoidal functors) 不需要是 endofunctors,所以我相信这些 可以 被扭转。让我们从“基本”定义开始:
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.
(练习:根据this定义派生的Applicative实例,反之亦然)
转身
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.
不知道这会有多大用处。 pureDisunit 肯定没用,因为它唯一的实现总是const ()。
让我们试着写一个明显的例子:
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!
我不认为这很有用,尽管您可以使用诸如巧妙的打结递归之类的东西来定义它。
可能更有趣的是一个逆变协单形函子,但这对我来说太奇怪了。