Scala中的协方差逆变误差

时间:2016-11-07 16:21:17

标签: scala covariance

我尝试编译以下代码:

class A[-T]
class B[-T] extends A[A[T]]

我收到以下错误:

error: contravariant type T occurs in covariant position in type [-T]A[A[T]]{def <init>(): B[T]} of class B

为什么这是一个错误?

2 个答案:

答案 0 :(得分:4)

这是一个错误,因为{T}中的A[A[T]]协变

来自Wikipedia的协变类型的定义:

  

在编程语言的类型系统中,键入规则或   类型构造函数是:

     
      
  • 协变如果它保留了类型(≤)的排序,它将类型从更具体的顺序排列到更通用的类型;
  •   
  • 逆变,如果它颠倒了这种顺序;
  •   

请考虑以下事项:

class Fruit
class Banana extends Fruit

Banana <: Fruit
A[Banana] :> A[Fruit] // Because A is contravariant in type T
A[A[Banana]] <: A[A[Fruit]] // Again because A is contravariant in type T

最后一个语句意味着A[A[T]]协变,因为它保留了类型的排序,从更具体到更通用。

所以可以这样做:

scala> type AA[+T] = A[A[T]]
defined type alias AA

scala> type AAA[-T] = A[A[A[T]]]
defined type alias AAA

但以下情况会导致错误:

scala> type AA[-T] = A[A[T]]
<console>:15: error: contravariant type T occurs in covariant position in type [-T]A[A[T]] of type AA
       type AA[-T] = A[A[T]]
            ^

scala> type AAA[+T] = A[A[A[T]]]
<console>:15: error: covariant type T occurs in contravariant position in type [+T]A[A[A[T]]] of type AAA
       type AAA[+T] = A[A[A[T]]]
            ^

最后回到原始问题,class B定义中的方差规则存在相同的违反,因为基类A[A[T]]在构造T中是协变的。

为了理解为什么禁止它,我们假设它是可能的:

class B[-T] extends A[A[T]]

在这种情况下,我们得到:

B[Fruit] <: B[Banana] <: A[A[Banana]] 

所以

val fruits: B[Fruit] = new B[Fruit]
val bananas1: B[Banana] = fruits
val bananas2: A[A[Banana]] = bananas1      

现在,我们的bananas2类型值A[A[Banana]]指向A[A[Fruit]]的{​​{1}}实例,该实例违反了A[A[Banana]] <: A[A[Fruit]]以来的类型安全性。

答案 1 :(得分:2)

<init>A(或B)的构造函数,由编译器定义。

代码的问题是B[-T] extends A[A[T]]会导致矛盾。

举个例子:

class A[-T]
class B[-T] extends A[A[T]]

class Animal
class Cat extends Animal

简而言之,让我们使用A <: B表示 AB 的子类型。

由于AB对其类型参数TCat <: Animal都是逆变的,因此

A[Animal] <: A[Cat]
B[Animal] <: B[Cat]

A[Animal] <: A[Cat]以来,(再次因为A的逆转):

A[A[Cat]] <: A[A[Animal]]

另外,根据B

的定义
B[Cat] = A[A[Cat]]
B[Animal] = A[A[Animal]]

我们已经知道B[Animal] <: B[Cat],但如果我们将这些类型转换为上述等值,我们会得到:

B[Animal] <: B[Cat] => A[A[Animal]] <: A[A[Cat]]

但我们已经证明了A[A[Cat]] <: A[A[Animal]]。我们最终会遇到一种不可能的情况。

相关问题