繁体   English   中英

为什么在Function1 [-A,+ B]中将第一个类型参数定义为逆变?

[英]why the first type parameter is defined as contravariant in Function1[-A, +B]?

所有读完Scala协方差/逆变问题及其答案由Daniel Spiewak提供,以及“Scala编程”一书的第19.3-19.7节,我对Function1 [-A,+ B]的定义有另一个疑惑:为什么它的第一种类型参数是逆变的吗? 我有一个原因,就是这个类型参数保证当有多种情况时,子类型总是出现在超类型之前,同时,子类型“是一个”超类型。 例如:

 class A
 class B extends A
 class C extends B
 scala> val withDefault: A => B = {
 | case x:B => new B
 | case x:A => new B }
 withDefault: A => B = <function1>

这里,(1) case x:B早于case x:A ,(2)功能1 [A,B] <:功能1 [B,B]并且必须有其他原因? 任何消息将不胜感激!

逆变性与模式匹配无关。 这就是为什么函数类型在它们的参数类型上是逆变的。 考虑这个功能:

def doHigherOrder(handleAnyAnimal: Animal => T,
                  anyAnimal:       Animal     ): T = {
  // ...foo...
  handleAnyAnimal(anyAnimal)
  // ...bar...
}

如果函数是协变而不是逆变,那么函数Duck => T也将是Animal => T的子类型,你可以做doHigherOrder(handleAnyDuck) 这将是一个错误因为那时,在doHigherOrderhandleAnyAnimal(anyAnimal)表达式将(在运行时/评估时)归结为handleAnyDuck(anyAnimal) ,这显然是不对的,因为可以处理任何Duck的函数可能无法处理任何Animal

def doHigherOrder(handleAnyDuck: Duck => T,
                  anyAnimal:     Animal   ): T = {
  // ...foo...
  handleAnyDuck(anyAnimal)  // <-- ERROR
  // ...bar...
}

此外,假设Creature >: Animal ,函数handleAnyCreature: Creature => T确实也是Animal => T的子类型,因为可以将anyAnimal传递anyAnimal可以接受anyCreature东西。

这就是为什么逆变在参数类型中直观上是不可避免的。


但是,返回值是协变的,因为它们具有与值完全相同的语义:

val animal = getDuck()    // ok
val duck   = getAnimal()  // <-- ERROR

与之比较

val x = handleDuck(animal)  // <-- ERROR
val y = handleAnimal(duck)  // ok

形象地说,你分配函数参数,但是它们的返回值。 使用命名参数变得更加明显:

val x = handle(duck   = animal) // <-- ERROR
val y = handle(animal = duck  ) // ok

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM