为什么 Haskell 中没有很多关于协变和逆变的讨论(相对于 Scala 或 C#)?

发布于 2025-01-06 00:06:08 字数 172 浏览 4 评论 0原文

我知道什么是类型的协变和逆变。我的问题是,为什么我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暖风昔人 2025-01-13 00:06:08

有两个主要原因:

  • Haskell 缺乏固有的子类型概念,因此一般来说方差不太相关。
  • 逆变主要出现在涉及可变性的地方,因此 Haskell 中的大多数数据类型只是协变的,并且明确区分它没有什么价值。

然而,这些概念确实适用——例如,fmap 对 Functor 实例执行的提升操作实际上是协变的;范畴论中使用术语“共变”/“逆变”来讨论函子。 contravariant 定义逆变函子的类型类,如果您查看实例列表,您就会明白为什么我说它不太常见。

在手动转换的工作方式中,还有一些地方隐式地体现了这个想法——各种数字类型类定义了与基本类型(如 Integer 和 Rational )之间的转换,以及模块 Data.List 包含一些标准函数的通用版本。如果您查看 这些通用版本的类型,您将看到 Integral 约束(给出 toInteger)用于逆变位置的类型,而 Num > 约束条件(给出fromInteger)用于协变位置。

There are two main reasons:

  • Haskell lacks an inherent notion of subtyping, so in general variance is less relevant.
  • Contravariance mostly appears where mutability is involved, so most data types in Haskell would simply be covariant and there'd be little value to distinguishing that explicitly.

However, the concepts do apply--for instance, the lifting operation performed by fmap for Functor instances is actually covariant; the terms co-/contravariance are used in Category Theory to talk about functors. The contravariant 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 and Rational, and the module Data.List contains generic versions of some standard functions. If you look at the types of these generic versions you'll see that Integral constraints (giving toInteger) are used on types in contravariant position, while Num constraints (giving fromInteger) are used for covariant position.

甜扑 2025-01-13 00:06:08

Haskell 中没有“子类型”,因此协变和逆变没有任何意义。

在 Scala 中,例如 Option[+A] 以及子类 Some[+A]None。您必须提供协方差注释 + 来表示如果 Foo 扩展 Bar,则 Option[Foo]Option[Bar]。由于子类型的存在,这是必要的。

在 Haskell 中,没有子类型。 Haskell 中 Option 的等价物称为 Maybe,具有以下定义:

data Maybe a = Nothing | Just a

类型变量 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 subclasses Some[+A] and None. You have to provide the covariance annotations + to say that an Option[Foo] is an Option[Bar] if Foo 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, called Maybe, has this definition:

data Maybe a = Nothing | Just a

The type variable a can only ever be one type, so no further information about it is necessary.

耶耶耶 2025-01-13 00:06:08

如前所述,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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文