【发布时间】:2023-01-09 03:49:57
【问题描述】:
作为对方差如何工作的探索,我想出了这种类型,它可以是 Functor 和 Contravariant,具体取决于它的参数:
newtype Shift f g a = Shift { runShift :: f a -> g a }
它类似于 Endo,除了使用额外的类型变量来使类型的变化不明确。
如果f是协变的而g是逆变的,那么Shift f g是逆变的:
instance (Functor f, Contravariant g) => Contravariant (Shift f g) where
contramap f (Shift g) = Shift (contramap f . g . fmap f)
如果 f 是逆变的并且 g 是协变的,那么 Shift f g 是协变的:
instance (Contravariant f, Functor g) => Functor (Shift f g) where
fmap f (Shift g) = Shift (fmap f . g . contramap f)
据我了解,Divisible(来自contravariant包中的Data.Functor.Contravariant.Divisible)是Contravariant,Applicative是Functor。使用它,Shift 也可以扩展为 Divisible 的实例:
instance (Functor f, Divisible g) => Divisible (Shift f g) where
conquer = Shift (const conquer)
divide f (Shift g) (Shift h) = Shift $
\x -> case unzipF (fmap f x) of
(b,c) -> divide f (g b) (h c)
unzipF :: Functor f => f (a,b) -> (f a,f b)
unzipF x = (fmap fst x, fmap snd x)
因为 Divisible (Shift f g) 上的约束是 (Functor f, Divisible g),所以我希望这会相应地“翻转” Applicative 实例,例如
instance (Contravariant f, Applicative g) => Applicative (Shift f g) where { ... }
但是,我不知道如何填写详细信息。我未完成的实现需要这样的功能:
unzipC :: Contravariant f => f (a,b) -> (f a,f b)
但我想不出不使用fmap 的解决方案。
这是完整的实现:
instance (Contravariant f, Applicative g) => Applicative (Shift f g) where
pure x = Shift (const (pure x))
liftA2 f (Shift g) (Shift h) = Shift $
\x -> case unzipC (contramap (uncurry f) x) of
(a,b) -> liftA2 f (g a) (h b)
那么,这样的unzipC 是否存在?如果不是,是否仍然可以挽救 Applicative (Shift f g) 实例?
【问题讨论】:
标签: haskell covariance applicative contravariance