我知道类型的协方差和逆变。我的问题是为什么我在Haskell的研究中没有遇到过对这些概念的讨论(而不是Scala)?
似乎Haskell查看类型与Scala或C#相反的方式存在根本区别,我想清楚地说明这种区别是什么。
或许我错了,我还没有学到足够的Haskell: - )
答案 0 :(得分:59)
主要有两个原因:
然而,这些概念确实适用 - 例如,fmap
对Functor
个实例执行的提升操作实际上是协变的;术语共同/逆变在类别理论中用于谈论仿函数。 contravariant
package为逆变函子定义了一个类型类,如果你查看实例列表,你就会明白为什么我说它不太常见。
还有一些地方隐含地显示了这个想法,手动转换的工作方式 - 各种数字类型类定义了与Integer
和Rational
等基本类型之间的转换,以及模块{ {1}}包含某些标准函数的通用版本。如果您查看the types of these generic versions,您会看到Data.List
约束(给出Integral
)用于逆变位置的类型,而toInteger
约束(给出Num
)用于协变位置。
答案 1 :(得分:21)
Haskell中没有“子类型”,所以协方差和逆变没有任何意义。
在Scala中,你有例如Option[+A]
子类Some[+A]
和None
。您必须提供协方差注释+
,以表明如果Option[Foo]
Option[Bar]
为Foo extends Bar
。由于存在子类型,这是必要的。
在Haskell中,没有子类型。 Haskell中的Option
等价于Maybe
,具有以下定义:
data Maybe a = Nothing | Just a
类型变量a
只能是一种类型,所以不需要有关它的更多信息。
答案 2 :(得分:7)
如前所述,Haskell没有子类型。但是,如果您正在查看类型类,可能不清楚如何在没有子类型的情况下工作。
类型类指定类型的谓词,而不是类型本身。因此,当Typeclass有一个超类(例如Eq a => Ord a)时,这并不意味着实例是子类型,因为只有谓词是继承的,而不是类型本身。
此外,共同,反对和方差在不同的数学领域意味着不同的东西(见维基百科)。例如,covariant和contravariant这两个术语用于仿函数(后者又用于Haskell),但这些术语意味着完全不同的东西。术语不变量可以在很多地方使用。