为什么没有关于Haskell(与Scala或C#相对)的协变和反变化的讨论?
我知道什么types的协变和逆变。 我的问题是为什么我在研究Haskell(而不是Scala)时还没有遇到这些概念的讨论?
Haskell的视图types与Scala或C#相比有一个根本的区别,我想说明一下这个区别是什么。
或者,也许我错了,我只是没有足够的Haskell学习:-)
主要有两个原因:
- Haskell缺乏子types的固有概念,所以一般而言,方差不太重要。
- 反variables主要出现在涉及可变性的地方,所以Haskell中的大多数数据types都是协变的,而且明确地区分这些数据types的价值不大。
然而,这些概念确实适用 – 例如,由fmap
为Functor
实例执行的提升操作实际上是协变的; 在类别理论中使用术语“共同/反对”来讨论函子。 contravariant
包为contravariant函子定义了一个types类,如果你看一下实例列表,你会明白为什么我说它不太常见。
这个想法也隐含地出现在人工转换如何工作的地方 – 各种数字types类定义了从Integer
和Rational
等基本types转换的模式,模块Data.List
包含了一些标准函数的通用版本。 如果你看看这些generics版本的types,你会发现Integral
约束(给予toInteger
)用于逆变位置的types,而Num
约束(来自fromInteger
)用于协变位置。
Haskell中没有“子types”,所以协变性和逆变性没有任何意义。
在斯卡拉,你有例如Option[+A]
的子类Some[+A]
和None
。 如果Foo extends Bar
则必须提供协方差标注+
来说明一个Option[Foo]
是一个Option[Bar]
。 由于子types的存在,这是必要的。
在Haskell中,没有子types。 Haskell中相当于叫做Maybe
的Option
有这样的定义:
data Maybe a = Nothing | Just a
typesvariablesa
只能是一个types,所以不需要进一步的信息。
如上所述,Haskell没有子types。 但是,如果你正在研究types类,那么可能不清楚如何在没有子types的情况下工作。
types类指定types的谓词,而不是types本身。 所以当Typeclass有一个超类(例如Eq a => Ord a)时,并不意味着实例是子types的,因为只有谓词是inheritance的,而不是types本身。
而且,在不同的math领域中,co-,contra-和in-in意味着不同的事物(参见维基百科)。 例如covariant和contravariant这两个术语被用在functor中(而Haskell又使用这个术语),但这些术语意味着完全不同的东西。 术语不变式可以在很多地方使用。