为什么Scala类型推理在这里失败

时间:2017-02-05 18:14:03

标签: scala generics functional-programming type-inference

为什么右关联运算符在泛型函数中存在问题,即使等效的左关联运算符也能正常工作。

implicit class FunctionWrapper[T1, T2](func: T1 => T2) {
  def >>>[T3](funcAfter: T2 => T3): T1 => T3 = {
    func andThen funcAfter
  }

  def >>:[T0](funcBefore: T0 => T1): T0 => T2 = {
    funcBefore andThen func
  }
}

以下是要链接的函数:

def intToFloat = Int.int2float _
def floatToString = (_: Float).toString
def identityF[T] = identity(_: T)

正如预期的那样,两个运营商都能很好地使用具体类型的功能:

scala> (intToFloat >>> floatToString)(11)
res5: String = 11.0

scala> (intToFloat >>: floatToString)(11)
res6: String = 11.0

但是,由于某种原因,>>:因通用类型函数而失败:

scala> (intToFloat >>> identityF >>> floatToString)(11)
res7: String = 11.0

scala> (intToFloat >>: identityF >>: floatToString)(11)
<console>:16: error: type mismatch;
 found   : Nothing => Nothing
 required: T0 => Float
       (intToFloat >>: identityF >>: floatToString)(11)
                                 ^

有一些解决方法,一个是

(intToFloat >>: (identityF (_: Float)) >>: floatToString)(11)

但是在给定的上下文中推断identityF的类型似乎很容易,为什么它会失败?

1 个答案:

答案 0 :(得分:2)

当你有一个右关联运算符时,请记住它真的

floatToString.>>:(identityF).>>:(intToFloat)

由于identityF没有给出类型参数,因此它受local type inference规则的约束。在这种情况下,它首先尝试查找identityF的类型参数(我认为,但反过来也会遇到麻烦);因为>>:的类型参数仍然是未知的,所以它不知道函数的参数类型。它通过推断Nothing而放弃,然后无法为>>:找到合适的类型参数。

使用andThen>>>,Scala已经知道identityF的预期参数类型,因此可以推断出正确的类型参数。

也就是说,问题不是>>:是正确关联的,它是参数和返回类型之间的不对称。如果您定义>>:[T0](f: T1 => T0),它将正常工作。