回想一下Applicative
类:
class Functor f => Applicative f where
pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
(<*>) :: f (a -> b) -> f a -> f b
liftA2 h x y = fmap h x <*> y
(<*>) = liftA2 id
虽然还不清楚如何用(数学)范畴论来表达这个类,但当定义以下函数时,它就变得清晰了:
liftZ2 :: Applicative f => (f a, f b) -> f (a, b)
liftZ2 (x, y) = liftA2 (,) x y
在这里,(,)
应该被识别为分类产品。将乘积替换为余积并反转所有箭头,得到以下类:
class Functor f => Coapplicative f where
copure :: f a -> a
coliftZ2 :: f (Either a b) -> Either (f a) (f b)
一些示例:
import Data.Functor.Identity
import qualified Data.List.NonEmpty as NonEmpty
import Data.Either
instance Coapplicative Identity where
copure (Identity x) = x
coliftZ2 (Identity (Left x)) = Left (Identity x)
coliftZ2 (Identity (Right y)) = Right (Identity y)
instance Coapplicative NonEmpty.NonEmpty where
copure (x NonEmpty.:| _) = x
coliftZ2 (Left x NonEmpty.:| xs) = Left (x NonEmpty.:| lefts xs)
coliftZ2 (Right y NonEmpty.:| ys) = Right (y NonEmpty.:| rights ys)
instance Coapplicative ((,) e) where
copure (_, x) = x
coliftZ2 (e, Left x) = Left (e, x)
coliftZ2 (e, Right y) = Right (e, y)
instance Monoid m => Coapplicative ((->) m) where
copure f = f mempty
coliftZ2 f = case copure f of
Left x -> Left (fromLeft x . f)
Right y -> Right (fromRight y . f)
我有一种强烈的直觉,Coapplicative
是Comonad
的超类,但我不知道如何证明这一点。另外,是否存在不是Comonad
的Coapplicative
示例?
1条答案
按热度按时间ckocjqey1#
这不是一个完整的答案,但我至少可以说明
Coapplicative NonEmpty
的示例不能单独从Comonad
方法派生;也就是说,如果存在那么它不会为
NonEmpty
生成示例。这是因为Comonad NonEmpty
的方法本身并不能改变列表的长度,但是coliftZ2
的NonEmpty
示例改变了列表的长度。因此,如果NonEmpty
要成为Coapplicative
,它必须以其他方式这样做,否则Coapplicative
不能是Comonad
的超类。当你进一步调查,我会说这是值得探讨的comonad
并考虑其
coliftZ2
实现必须是什么。你还没有给出Coapplicative
的任何定律,但是如果你有,我会把我的钱放在打破它们上,因为没有coliftZ2
的实现是令人满意的对称的。以下两个等式都是相当强迫的,但它们似乎表明了非常不同的操作意图:在我看来,最能说明这一点的问题是:我们应该期待
coliftZ2
与comonad方法的 * 关系 * 是什么?