【发布时间】:2021-09-30 02:29:57
【问题描述】:
我在玩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
在实现Contravariant 和@ 的实例时,我们将免除程序员重写此phantom 两次(以实现fmap 和contramap,即const phantom,如注释中所述)的必要性987654350@。我们将允许编写一个实例而不是两个!此外,对我来说,为所有 4 种差异情况提供类似乎很好且惯用:Functor、Contravariant、Invariant(然而,some 建议使用Profunctor 接口而不是Invariant),以及Phantom.
另外,这不是更高效的方法吗? () <$ x $< () 需要两次遍历(只要我们可以遍历一个幻像函子......),只要程序员可以更快地执行这个转换。据我了解,当前的phantom 方法不能被覆盖。
那么,为什么库开发者不选择这种方式呢?目前的设计和我所说的设计的优缺点是什么?
【问题讨论】:
-
phantom不是Functor或Contravariant的方法。您不需要“重写两次”甚至一次。 -
@FyodorSoikin 你这样做,实现
fmap和contramap,它们是const phantom。抱歉措辞不好 -
嗯,有,比如...
Proxy和Const和... 还有什么,究竟是什么? (实际上,每种幻像类型都是Const伪装的。)您可能会节省五秒钟的程序员时间,就像每十年一次一样。感觉很难为此激动。
标签: haskell covariance functor contravariance library-design