为什么 Scala 类型推断在这里失败
Why does Scala type inferencing fail here
为什么右结合运算符在泛型函数中存在问题,尽管等效的左结合运算符工作得很好。
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 的类型似乎很容易,为什么会失败?
当你有一个 right-associative 运算符时,记住它真的是
floatToString.>>:(identityF).>>:(intToFloat)
由于 identityF
没有指定类型参数,因此它受 local type inference 规则约束。在这种情况下,它首先尝试找到 identityF
的类型参数(我认为,但反过来也会遇到麻烦);因为 >>:
的类型参数仍然未知,所以它不知道函数的参数类型。它通过推断 Nothing
而放弃,然后未能为 >>:
.
找到合适的类型参数
使用 andThen
或 >>>
,Scala 已经知道 identityF
的预期参数类型,因此可以推断出正确的类型参数。
也就是说,问题不是 >>:
是 right-associative,而是参数和 return 类型之间的不对称。如果您定义 >>:[T0](f: T1 => T0)
它将正常工作。
为什么右结合运算符在泛型函数中存在问题,尽管等效的左结合运算符工作得很好。
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 的类型似乎很容易,为什么会失败?
当你有一个 right-associative 运算符时,记住它真的是
floatToString.>>:(identityF).>>:(intToFloat)
由于 identityF
没有指定类型参数,因此它受 local type inference 规则约束。在这种情况下,它首先尝试找到 identityF
的类型参数(我认为,但反过来也会遇到麻烦);因为 >>:
的类型参数仍然未知,所以它不知道函数的参数类型。它通过推断 Nothing
而放弃,然后未能为 >>:
.
使用 andThen
或 >>>
,Scala 已经知道 identityF
的预期参数类型,因此可以推断出正确的类型参数。
也就是说,问题不是 >>:
是 right-associative,而是参数和 return 类型之间的不对称。如果您定义 >>:[T0](f: T1 => T0)
它将正常工作。