类型推断器如何在reduceLeft上工作?

时间:2011-12-03 02:04:46

标签: scala type-inference scala-collections type-bounds

reduceLeft reduceLeft Seq以后,def reduceLeft [B >: A] (f: (B, A) ⇒ B): B List(1,2,3,4) reduceLeft (_ + _) 的签名是

A

我们可以用

等表达式来调用它
Int

在此示例中,reduceLeftFunction2[B >: Int, Int, B],因此B需要+。无论reduceLeft如何工作(这是无关紧要的),类型推断器如何知道Any具有{{1}}方法,何时它可以是{{1}}类型?

2 个答案:

答案 0 :(得分:4)

我认为spec类的 6.26.4 Local Type Inference 部分解释了正在发生的事情。编译器将寻找最佳类型。当类型参数是逆变时,所选择的类型将是最大的(在本例中为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

答案 1 :(得分:1)

如果B&gt;: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