【问题标题】:How does the type inferencer work on reduceLeft?类型推断器如何在 reduceLeft 上工作?
【发布时间】:2011-12-03 02:04:46
【问题描述】:

my other question关于reduceLeft外,reduceLeftSeq上的签名是

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

我们可以用诸如

这样的表达式来调用它
List(1,2,3,4) reduceLeft (_ + _)

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

【问题讨论】:

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


    【解决方案1】:

    我认为spec6.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) =&gt; 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) =&gt; Int

    【讨论】:

      【解决方案2】:

      如果 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-06-20
        • 1970-01-01
        • 2012-10-14
        • 1970-01-01
        • 2021-07-03
        • 1970-01-01
        • 2021-01-01
        • 1970-01-01
        相关资源
        最近更新 更多