函子可以是协变的或者逆变的。这种协变/逆变的双重性质是否也适用于单子?
类似这样:
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
类有意义吗?有示例吗?
函子可以是协变的或者逆变的。这种协变/逆变的双重性质是否也适用于单子?
类似这样:
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
类有意义吗?有示例吗?
当然,定义它是可能的,但我怀疑它是否有任何用处。
有一句流行的说法,“单子仅仅是自函子范畴中的幺半群”。这意味着,首先,我们有一个自函子范畴(即,从某个范畴到其自身的共变函子),而且更重要的是,我们对这些自函子进行了某种乘法运算(在这种情况下是组合)。然后单子适合于我们现在不必担心的一般框架中。关键是,反变函子没有“乘法”。两个共变函子的组合仍然是一个共变函子;但是两个反变函子的组合并不是一个反变函子(相反,它是一个共变函子,因此是完全不同的东西)。
因此,“反变单子”实际上没有意义。
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)
但是共函子仍然是协变函子。
与单子不同,应用函子(幺半范畴)不需要是自函子,因此我认为这些可以被反转。让我们从“基本”定义开始:
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!
我认为这并不是有用的,尽管你可能可以通过类似巧妙的绳结递归来定义它。
更有趣的可能是一个逆变共单子函子,但这对我来说现在太奇怪了。
fmap :: (a -> b) -> (m a -> m b)
,它可以被反转。 - ZhekaKozlovpure
和join
是不够的。如果不相信,请尝试仅使用pure
和join
来实现bind
。 - ZhekaKozlovFunctor
超类了。 - leftaroundabout