3

除了我的另一个问题之外,onreduceLeft的签名是reduceLeftSeq

def reduceLeft [B >: A] (f: (B, A) ⇒ B): B 

我们可以用诸如

List(1,2,3,4) reduceLeft (_ + _)

在此示例A中是Int,因此reduceLeft需要 Function2[B >: Int, Int, B]. 不管 reduceLeft 是如何工作的(这无关紧要),类型推断器如何知道B有一个+方法,什么时候它可能是 type Any

4

2 回答 2

4

我认为规范的6.26.4局部类型推断部分解释了发生了什么。编译器将寻找最佳类型。当类型参数是逆变的时,选择的类型将是最大的(在这种情况下是 Any),否则(不变或协变)是最小的(在这种情况下是 Int)。

有几个我无法真正理解的例子reduceLeft

我注意到的是,在查看传递的匿名函数之前,推理似乎发生了:

scala> List(1,2).reduceLeft[Any](_.toString + _)
res26: Any = 12

但如果我不帮助类型推断器:

scala> List(1,2).reduceLeft(_.toString + _)
<console>:8: error: type mismatch;
 found   : java.lang.String
 required: Int
              List(1,2).reduceLeft(_.toString + _)

编辑,我错了,考虑到匿名函数,这有效:

List(1,2).reduceLeft((_:Any).toString + (_:Any).toString)

有一个-Ytyper-debug可以运行的编译器选项:

List(1,2).reduceLeft(_+_)

它会告诉你编译器以某种方式假定匿名函数的预期类型是(Int, Int) => Int,然后它继续检查_ + _它并成功,然后推断BInt。此处摘录:

typed immutable.this.List.apply[Int](1, 2).reduceLeft: [B >: Int](f: (B, Int) => B)B
adapted immutable.this.List.apply[Int](1, 2).reduceLeft: [B >: Int](f: (B, Int) => B)B to ?, undetparams=type B
typing ((x$1, x$2) => x$1.$plus(x$2)): pt = (Int, Int) => Int: undetparams=, 
// some time later 
typed ((x$1: Int, x$2: Int) => x$1.+(x$2)): (Int, Int) => Int
adapted ((x$1: Int, x$2: Int) => x$1.+(x$2)): (Int, Int) => Int to (Int, Int) => Int, 
typed immutable.this.List.apply[Int](1, 2).reduceLeft[Int](((x$1: Int, x$2: Int) => x$1.+(x$2))): Int

我不知道为什么在没有类型归属的情况下假定匿名函数是(Int, Int) => Int.

于 2011-12-03T04:34:15.777 回答
1

如果 B >: X 并且编译器知道 X 但无法解析 B,则它只是假设 B = X。

它有点实用,因为它只有 B 的两个选项,并且只有一个是已知的。所以不知道它假设 B 是哪个超类 X。您可以使用以下代码测试编译器的决策过程。

class Y {
  def bar(y:Y) = this
}
case class X( i: Int ) extends Y {
  def foo(x:X)=X(i+x.i)
}
val t = new Y bar X(7)
val t2 = X(8) bar X(7)
val res = List(X(1),X(2),X(3)) reduceLeft { _ foo _ }
val res2 = List(X(1),X(2),X(3)) reduceLeft { _ bar _ } // will not compile
于 2011-12-03T04:27:26.587 回答