为什么不是扩展FunctorContravariant的Phantom类?

我在玩弄Data.Functor.Contravariant. 该phantom方法引起了我的注意:

phantom :: (Functor f, Contravariant f) => f a -> f b
phantom x = () <$ x $< ()

或者,更具体地说,对它的注释:

如果f两者都是FunctorContravariant那么当您考虑每个类别的法律时,它实际上无法以任何有意义的能力使用它的论点。这种方法非常有用。当这两种情况存在,是合法的,我们有以下规律:fmap f ? phantomcontramap f ? phantom

既然fmap f ? contramap f ? phantom,为什么我们需要ContravariantFunctor实例?用另一种方式做这件事不是更方便:为一个类创建一个实例Phantom,它引入了phantom方法,然后自动Functor派生实例Contravariant?

class Phantom f where
    phantom :: f a -> f b

instance Phantom f => Functor f where
    fmap _f = phantom

instance Phantom f => Contravariant f where
    contramap _f = phantom

我们将摆脱必然性的程序员改写这个phantom两次(实施fmapcontramap,这是const phantom实现实例时,作为注解说明)ContravariantFunctor。我们将允许编写一个实例而不是两个!此外,它似乎不错,地道到我对所有4案件方差类:FunctorContravariantInvariant(然而,有些人建议使用Profunctorinterface 而不是Invariant),和Phantom

另外,这不是更有效的方法吗?() <$ x $< ()需要两次遍历(就像我们可以遍历一个幻影函子一样......),只要程序员可以更快地执行这个转换。据我了解,当前的phantom方法不能被覆盖。

那么,库开发者为什么不选择这种方式呢?目前的设计和我所说的设计的优缺点是什么?

回答

有许多类型是 Functor 的实例而不是 Phantom 的实例,同样是逆变的。对于此类类型,由于实例重叠,您提出的结构将是一个大问题。

instance Phantom f => Functor f

并不意味着“如果f是 Phantom 那么它也是一个 Functor”。在类型类解析期间只搜索实例头,约束稍后出现。这与开放世界假设有关。因此,您为 声明了一个 Functor 实例f,这是一个完全不受约束的类型变量,它将与所有其他可能的实例声明重叠。


以上是为什么不是扩展FunctorContravariant的Phantom类?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>