为什么在Haskell中很少讨论协变和逆变(与Scala或C#相比)?

61
我知道什么是类型的协变和逆变。我的问题是为什么在学习Haskell时(而不是例如Scala),我还没有遇到这些概念的讨论?
似乎Haskell对类型的看法与Scala或C#有根本性的区别,我想表达这种差异。
或者我可能是错的,我还没有学足够的Haskell :-)

2
好久不见,但我似乎记得这个视频中有一些关于协变/逆变的函数式/Haskellish对话:http://channel9.msdn.com/shows/Going+Deep/E2E-Brian-Beckman-and-Erik-Meijer-CoContravariance-in-Physics-and-Programming-2-of-2/ - steamer25
3个回答

62

主要有两个原因:

  • Haskell缺乏子类型的内在概念,因此通常情况下变异性不太相关。
  • 协变逆变大多出现在涉及可变性的地方,因此Haskell中大多数数据类型只会是协变的,并且区分它们没有太多价值。

然而,这些概念确实适用——例如,Functor实例的提升操作由fmap执行实际上是协变的;在范畴论中,术语协变/逆变用于讨论函子。 contravariant为逆变函子定义了一个类型类,如果您查看实例列表,就会看到我为什么说它非常不常见。

这个想法也隐含地出现在手动转换的各个地方——各种数字类型类定义到基本类型(如IntegerRational)的转换,以及模块Data.List包含一些标准函数的通用版本。如果您查看这些通用版本的类型,您将看到逆变位置上的类型使用Integral限制(给出toInteger),而协变位置上使用Num限制(给出fromInteger)。


7
我认为不同变性与可变性之间没有关系。事实上,可变性会导致不变性。反变性的例子包括函数输入、OrdEq(当然它们的等效物),它们甚至都没有数据可以被改变。 - Daniel C. Sobral
14
写入可变引用是反变的,是函数输入的特殊情况。因此,虽然简单数据类型通常允许协变,但允许逆变的类型往往表示汇聚或输出,除非涉及某些副作用,否则它们可能是微不足道的。但带有读写操作的可变引用必须是不变的。 - C. A. McCann
@Daniel,协变性与可变性相关的问题可以在Snap Framework的Snaplet API提供的with函数中看到。它被设计成允许易于操作“可变”状态的层次结构。 - mightybyte
6
我以前从未注意到 NumIntegral 是如此对偶的! - J. Abrahamson
3
术语上有些混淆了。您说 "types that allow contravariance tend to represent sinks or outputs"——例如函数输入。使用 "sinks or outputs" 和 "function inputs" 似乎是自相矛盾的。据我所知,函数输入是逆变的,而函数输出是协变的。我认为您想表达的是函数输入就像流入函数的汇点。因此它是函数的输出(这意味着它是输入)。我理解正确吗?对不起,我只是非常困惑。 - Aadit M Shah
3
你说得对,无论是概念还是我不幸选择的措辞都是如此。:] 在调用函数时,它的参数是输出,但对于函数体来说,它们是输入。问题在于调用者和被调用者的角度,在它们之间切换会使所有变化反转。上面,我用“inputs”表示“parameters”,同时从调用者的角度谈论,因此造成了混淆。同样适用于函数返回值(带有相反的差异),它们有效地是“输出到调用者的连续中”。 - C. A. McCann

22
在Haskell中,不存在“子类型”,因此协变和逆变没有任何意义。在Scala中,你有例如Option[+A]的类,带有子类Some[+A]None。你必须提供协变注释+来表示如果Foo extends Bar,那么Option[Foo]Option[Bar]。由于存在子类型,这是必需的。在Haskell中,不存在子类型。在Haskell中,称为MaybeOption等效类型有以下定义:
data Maybe a = Nothing | Just a

类型变量a只能是一种类型,因此不需要更多关于它的信息。


10
正如提到的那样,Haskell没有子类型。但是,如果您正在查看类型类,则可能不清楚在没有子类型的情况下如何工作。
类型类指定类型上的谓词,而不是类型本身。因此,当一个类型类有一个超类(例如Eq a => Ord a),这并不意味着实例是子类型,因为只有谓词被继承,而不是类型本身。
此外,共变、反变和不变在数学的不同领域中具有不同的含义(请参见维基百科)。例如,协变和逆变术语用于函子(这又用于Haskell),但这些术语的含义完全不同。不变量术语可以用于很多地方。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接