Functors可以是协变的和逆变的。这种协变/逆变二元性是否也适用于monad?
类似的东西:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
class ContraMonad m where
return :: a -> m a
contrabind :: m a -> (b -> m a) -> m b
ContraMonad
课程有意义吗?有什么例子吗?
答案 0 :(得分:23)
当然,可以定义它,但我怀疑它会有用。
有一种流行的说法是“monad只是一种类型的endofunctors中的monoid”。这意味着,首先,我们有一类endofunctors(意思是,从一些类别到其自身的(协变)函子),而且我们在这个endofunctors上有一些乘法(在这种情况下 - 组合)。然后monad适合我们现在不必担心的一般框架。关键是,逆变函子没有“乘法”。两个协变仿函数的组合又是一个协变函子;但是两个逆变函子的组合不是逆变函子(而是一个协变函子,所以,一个完全不同的野兽)。
所以,“逆变单子”并没有真正意义。
答案 1 :(得分:15)
逆变函子是一个从一个类到opposite category的函子,即从一个类到另一个类(尽管是密切相关的)。 OTOH,monad最重要的是 endofunctor ,即从一个类别到本身。所以它不能逆变。
当你考虑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)
但是comonads仍然是协变仿函数。
与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.
(练习:根据此定义派生的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!
我认为这不是很有用,尽管你可以用聪明的结合递归来定义它。
可能更有趣的是一个逆变共同幺正函子,但现在这对我来说太奇怪了。