为什么 Haskell 中没有很多关于协变和逆变的讨论(相对于 Scala 或 C#)?
我知道什么是类型的协变和逆变。我的问题是,为什么我在 Haskell(相对于 Scala)的研究中还没有遇到过对这些概念的讨论?
与 Scala 或 C# 相比,Haskell 看待类型的方式似乎存在根本差异,我想阐明这种差异是什么。
或者也许我错了,我只是还没有学到足够的 Haskell :-)
I know what covariance and contravariance of types are. My question is why haven't I encountered discussion of these concepts yet in my study of Haskell (as opposed to, say, Scala)?
It seems there is a fundamental difference in the way Haskell views types as opposed to Scala or C#, and I'd like to articulate what that difference is.
Or maybe I'm wrong and I just haven't learned enough Haskell yet :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有两个主要原因:
然而,这些概念确实适用——例如,fmap 对 Functor 实例执行的提升操作实际上是协变的;范畴论中使用术语“共变”/“逆变”来讨论函子。
contravariant
包 定义逆变函子的类型类,如果您查看实例列表,您就会明白为什么我说它不太常见。在手动转换的工作方式中,还有一些地方隐式地体现了这个想法——各种数字类型类定义了与基本类型(如 Integer 和 Rational )之间的转换,以及模块
Data.List
包含一些标准函数的通用版本。如果您查看 这些通用版本的类型,您将看到Integral
约束(给出toInteger
)用于逆变位置的类型,而Num
> 约束条件(给出fromInteger
)用于协变位置。There are two main reasons:
However, the concepts do apply--for instance, the lifting operation performed by
fmap
forFunctor
instances is actually covariant; the terms co-/contravariance are used in Category Theory to talk about functors. Thecontravariant
package defines a type class for contravariant functors, and if you look at the instance list you'll see why I said it's much less common.There are also places where the idea shows up implicitly, in how manual conversions work--the various numeric type classes define conversions to and from basic types like
Integer
andRational
, and the moduleData.List
contains generic versions of some standard functions. If you look at the types of these generic versions you'll see thatIntegral
constraints (givingtoInteger
) are used on types in contravariant position, whileNum
constraints (givingfromInteger
) are used for covariant position.Haskell 中没有“子类型”,因此协变和逆变没有任何意义。
在 Scala 中,例如
Option[+A]
以及子类Some[+A]
和None
。您必须提供协方差注释+
来表示如果Foo 扩展 Bar,则
。由于子类型的存在,这是必要的。Option[Foo]
是Option[Bar]
在 Haskell 中,没有子类型。 Haskell 中
Option
的等价物称为Maybe
,具有以下定义:类型变量
a
只能是一种类型,因此没有更多信息关于它是必要的。There are no "sub-types" in Haskell, so covariance and contravariance don't make any sense.
In Scala, you have e.g.
Option[+A]
with the subclassesSome[+A]
andNone
. You have to provide the covariance annotations+
to say that anOption[Foo]
is anOption[Bar]
ifFoo extends Bar
. Because of the presence of sub-types, this is necessary.In Haskell, there are no sub-types. The equivalent of
Option
in Haskell, calledMaybe
, has this definition:The type variable
a
can only ever be one type, so no further information about it is necessary.如前所述,Haskell 没有子类型。但是,如果您正在查看类型类,则可能不清楚在没有子类型的情况下它是如何工作的。
类型类指定类型的谓词,而不是类型本身。因此,当 Typeclass 有超类(例如 Eq a => Ord a)时,并不意味着实例是子类型,因为只有谓词被继承,而不是类型本身。
此外,同方差、反方差和不变性在不同的数学领域中意味着不同的事物(参见维基百科)。例如,术语“协变”和“逆变”用在函子中(函子又用在 Haskell 中),但这些术语的含义完全不同。术语不变量可以用在很多地方。
As mentioned, Haskell does not have subtypes. However, if you're looking at typeclasses it may not be clear how that works without subtyping.
Typeclasses specify predicates on types, not types themselves. So when a Typeclass has a superclass (e.g. Eq a => Ord a), that doesn't mean instances are subtypes, because only the predicates are inherited, not the types themselves.
Also, co-, contra-, and in- variance mean different things in different fields of math (see Wikipedia). For example the terms covariant and contravariant are used in functors (which in turn are used in Haskell), but the terms mean something completely different. The term invariant can be used in a lot of places.