什么时候Scala需要匿名和扩展函数的参数类型?

Jea*_*let 7 scala type-inference anonymous-function

什么时候Scala编译器真的需要匿名函数参数的类型信息?

例如,给定此功能:

def callOn[T,R](target: T, f: (T => R)) = f(target)
Run Code Online (Sandbox Code Playgroud)

然后我不能这样使用它:

callOn(4, _.toString)
  => error: missing parameter type for expanded function ((x$1) => x$1.toString)
Run Code Online (Sandbox Code Playgroud)

我必须指明

callOn(4, (_: Int).toString)
Run Code Online (Sandbox Code Playgroud)

这是相当丑陋的.为什么我的示例不起作用,而集合类上的map,filter,foldLeft等方法似乎不需要这种显式类型?

Kev*_*ght 14

类型推断的技巧是将其视为迭代细化的过程.每个参数块可用于推断一些类型参数,然后可以在后续块中使用.所以采取以下定义:

def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x))
Run Code Online (Sandbox Code Playgroud)

称为:

chain(2)(_*10)("xxx"+_)
Run Code Online (Sandbox Code Playgroud)

那么这是怎么推断出来的呢?首先,我们从(2)已知具有该类型的块开始Int.将其替换回T我们得到的参数:

def chain[A,B](x: Int)(fn1: Int=>A)(fn2: A=>B) = fn2(fn1(x))
Run Code Online (Sandbox Code Playgroud)

下一个参数块(_*10),我们现在知道的占位符的类型_Int......再乘以一个IntInt给出了另一个Int.即使发生溢出,返回类型也是如此; 在极端,它可能抛出一个异常,但异常的类型Nothing是类型系统中其他所有东西的子类,所以我们仍然可以说Nothingis-an Int和推断类型Int仍然有效.

通过A推断,该方法变为:

def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x))
Run Code Online (Sandbox Code Playgroud)

只留下B哪些可以推断出来("xxx"+_).由于String + IntString,该方法现在是:

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String) = fn2(fn1(x))
Run Code Online (Sandbox Code Playgroud)

由于方法的返回类型来自直接fn2,也可以明确显示完整性:

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String): String = fn2(fn1(x))
Run Code Online (Sandbox Code Playgroud)

你有它,所有类型都安全地解决了,并且该方法被证明是静态有效的.


在您的情况下,您需要在T可以R从类型推断之前推断类型T=>R.为此,您必须将参数拆分为两个不同的块,以咖喱形式编写方法:

def callOn[T,R](target: T)(f: (T => R)) = f(target)
Run Code Online (Sandbox Code Playgroud)


Wil*_*ger 6

这个问题在这里也有答案:

为所有适用类型传递函数

您期望,......对于Scala的编译器,要将两个参数都考虑到两次,以推断出正确的类型.但是,Scala并没有这样做 - 它只使用从一个参数列表到下一个参数列表的信息,而不是从一个参数到下一个参数.这意味着独立地分析参数f和a [WS:在这种情况下的目标和f],而没有知道另一个是什么的优点.

请注意,它确实有咖喱版本的工作:

scala> def callOn[T,R](target: T)(f: (T => R)) = f(target)
callOn: [T,R](target: T)(f: (T) => R)R

scala> callOn(4)(_.toString)
res0: java.lang.String = 4

scala> 
Run Code Online (Sandbox Code Playgroud)