我正在玩弄Data.Functor.Contravariant
. 该phantom
方法引起了我的注意:
phantom :: (Functor f, Contravariant f) => f a -> f b
phantom x = () <$ x $< ()
或者,更具体地说,它的注释:
如果
f
两者兼而有之Functor
,Contravariant
那么当您考虑到每个类的定律时,它实际上就不能以任何有意义的能力使用它的论点。这种方法非常有用。fmap f ≡ phantom
在这两种情况都存在且合法的情况下,我们有以下法律:contramap f ≡ phantom
既然fmap f ≡ contramap f ≡ phantom
,为什么我们需要Contravariant
和Functor
实例?以另一种方式做这件事不是更方便:为一个类创建一个实例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
在实现and的实例时,我们将让程序员不必重写它phantom
两次(以实现fmap
and contramap
,const phantom
如注释中所述)。我们将允许编写一个实例而不是两个!此外,对我来说,为所有 4 种差异情况都有类似乎很好而且很惯用:, , (然而,有些人建议使用interface 而不是) 和.Contravariant
Functor
Functor
Contravariant
Invariant
Profunctor
Invariant
Phantom
另外,这不是更有效的方法吗?() <$ x $< ()
需要两次遍历(就像我们可以遍历一个幻象函子一样......),只要程序员可以更快地执行这个转换。据我了解,当前phantom
方法不能被覆盖。
那么,为什么库开发者不选择这种方式呢?目前的设计和我所说的设计的优缺点是什么?