为什么方法的类型位置被标记为否定?

时间:2014-04-29 15:50:09

标签: scala contravariance type-systems

对不起,我已经问了一些像这样的问题,但我仍然无法得到一个明确的答案,也许我的英语不好,表达方式不清楚使那些善良的人感到困惑。

当我阅读"类型参数化"在本文中:http://www.artima.com/pins1ed/type-parameterization.html,我看到有关类型位置的一些解释:

  

作为一个有点人为的例子,考虑以下类定义,其中几个位置的方差用^ +(对于正数)或^ - (对于负数)进行注释:

   abstract class Cat[-T, +U] {
     def meow[W^-](volume: T^-, listener: Cat[U^+, T^-]^-)
     : Cat[Cat[U^+, T^-]^-, U^+]^+
   }

W位置外,我能理解这堂课的大部分内容。我不明白为什么它标记为否定,整篇文档中没有解释。

它还说:

  

用+注释的类型参数只能在正位置使用,而用 - 注释的类型参数只能在负位置使用。

如何在位置-中找到W注释的类型以适应此负面位置?

2 个答案:

答案 0 :(得分:4)

语言参考说:

  • 方法参数的方差位置与封闭参数子句的方差位置相反。
  • 类型参数的方差位置与封闭类型参数子句的方差位置相反。
  • 类型声明或类型参数的下限的方差位置与类型声明或参数的方差位置相反。

确定类型参数具有方差位置意味着什么?

class Moo[+A, -B] {
  def foo[X] (bar : Y) ...

所以Y处于逆向位置,这很明显。我们可以把B放在它的位置,但不是A。

但是X在逆变位置意味着什么?我们不能替代A或B或其他任何东西,它只是一个正式的参数!

这是真的,但是这个东西可以有从属位置,它们是类型,并且有变化。所以我们需要在跟踪我们翻转方差的次数时计算X的位置。这里没有X的从属条款,但请考虑一下:

class Moo[+A, -B] {
  def foo[X >: Z] (bar : B) ...

我们可能用A或B代替Z,但哪个是正确的?那么,Z的位置与X的位置相反,并且X的位置与顶层的位置相反,这是协变的,因此Z也必须是协变的。我们来看看:

abstract class Moo[+A, -B] {
      def foo[X >: A] (bar : B)
}    
defined class Moo

看起来我们是对的!

答案 1 :(得分:1)

规范中有一个熟悉的例子:

http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#variance-annotations

Sequence.append是pdf中的示例4.5.2,但目前没有编号。

abstract class Sequence[+A] {
  def append[B >: A](x: Sequence[B]): Sequence[B]
}

在现实生活中,请参阅the doc for Seq.++,忽略“用例”并点击“完整签名”以显示下限。

这与其他扩展操作(例如Option.getOrElse)的模式相同,您可以获得比您开始时更广泛的类型。

这是一个在替代方面有意义的例子:

鉴于Seq[Fruit],我可以追加Seq[Orange]。自Apple <: Fruit起,我还可以将橘子追加到Seq[Apple]并获得水果。

这就是B类型参数想要被协变参数绑定的原因。出于方差检查的目的,B的方差位置被归类为负值,但B本身未注释。

有趣的是,这解析了:

scala> trait X { def append[-](): Unit }
defined trait X