多参数列表方法
对于类型推断
具有多个参数部分的方法可用于辅助本地类型推断,方法是使用第一部分中的参数来推断类型参数,该类型参数将为后续部分中的参数提供预期类型。foldLeft
在标准库中就是典型的例子。
def foldLeft[B](z: B)(op: (B, A) => B): B
List("").foldLeft(0)(_ + _.length)
如果这是这样写的:
def foldLeft[B](z: B, op: (B, A) => B): B
必须提供更明确的类型:
List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)
对于流畅的 API
多参数部分方法的另一个用途是创建一个看起来像语言结构的 API。调用者可以使用大括号代替圆括号。
def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)
loop(2) {
println("hello!")
}
将 N 个参数列表应用于具有 M 个参数部分的方法,其中 N < M,可以显式转换为具有 a 的函数_
,或隐式转换为具有预期类型的函数FunctionN[..]
。这是一项安全功能,有关背景信息,请参阅 Scala 参考中的 Scala 2.0 更改说明。
咖喱函数
Curried 函数(或者简单地说,返回函数的函数)更容易应用于 N 个参数列表。
val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)
这种小小的便利有时是值得的。请注意,函数不能是参数类型,因此在某些情况下需要方法。
您的第二个示例是混合:返回函数的单参数部分方法。
多阶段计算
柯里化函数还有什么用处?这是一个一直出现的模式:
def v(t: Double, k: Double): Double = {
// expensive computation based only on t
val ft = f(t)
g(ft, k)
}
v(1, 1); v(1, 2);
我们如何分享结果f(t)
?一个常见的解决方案是提供一个矢量化版本v
:
def v(t: Double, ks: Seq[Double]: Seq[Double] = {
val ft = f(t)
ks map {k => g(ft, k)}
}
丑陋的!我们已经纠缠了不相关的问题——计算g(f(t), k)
和映射一系列ks
.
val v = { (t: Double) =>
val ft = f(t)
(k: Double) => g(ft, k)
}
val t = 1
val ks = Seq(1, 2)
val vs = ks map (v(t))
我们还可以使用返回函数的方法。在这种情况下,它更具可读性:
def v(t:Double): Double => Double = {
val ft = f(t)
(k: Double) => g(ft, k)
}
但是如果我们尝试对具有多个参数部分的方法做同样的事情,我们就会卡住:
def v(t: Double)(k: Double): Double = {
^
`-- Can't insert computation here!
}