Несколько методов списка параметров
Для вывода типа
Методы с несколькими разделами параметров могут использоваться для облегчения локального вывода типа, используя параметры в первом разделе, чтобы вывести аргументы типа, которые обеспечат ожидаемый тип для аргумента в следующем разделе. 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 _ или неявно с ожидаемым типом FunctionN[..]
. Это функция безопасности, см. Примечания к изменениям для Scala 2.0, в Справочниках Scala, для фона.
Функции 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!
}