【问题标题】:Can an Applicative instance for this type be created?可以为这种类型创建应用实例吗?
【发布时间】:2023-01-09 03:49:57
【问题描述】:

作为对方差如何工作的探索,我想出了这种类型,它可以是 FunctorContravariant,具体取决于它的参数:

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)是ContravariantApplicativeFunctor。使用它,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


    【解决方案1】:

    不,这样的(总)功能是不存在的。请注意,它允许您构造一个类型为 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) ()
    

    解释:((), Void) -> Void 类型由 snd 居住。 unzipC 会让你从((), Void) -> Void 得到一个() -> Void 和一个Void -> Void,但是() -> Void 显然无人居住。

    我不确定是否还有另一种方法来编写您想要的实例。当/如果我弄清楚了,我会编辑这个答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-20
      • 2022-11-18
      • 2013-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多