为了探索方差是如何工作的,我提出了这种类型,它可以是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 (从Data.Functor.Contravariant.Divisible到contravariant包)是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)实例?
发布于 2022-07-09 00:54:31
不,这样的(总)函数不可能存在。注意,它将允许您构造一个类型为Void的值。
import Data.Functor.Contravariant
import Data.Void
unzipC :: Contravariant f => f (a,b) -> (f a,f b)
unzipC = undefined
uhoh :: Void
uhoh = getOp (fst $ unzipC $ Op snd) ()我不确定是否还有其他方法来编写您想要的实例。如果我搞清楚了,我会编辑这个答案。
https://stackoverflow.com/questions/72918092
复制相似问题