Методы с несколькими параметрами
Для вывода типа
Для облегчения вывода локального типа можно использовать методы с несколькими разделами параметров, используя параметры в первом разделе для вывода аргументов типа, которые предоставят ожидаемый тип для аргумента в следующем разделе. 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, может быть преобразовано в функцию явно с _
или неявно с ожидаемым типом FunctionN[..]
. Это функция безопасности, справочную информацию см. В примечаниях к изменениям для Scala 2.0 в Справочниках по Scala.
Карри-функции
Каррированные функции (или просто функции, возвращающие функции) легче применять к N спискам аргументов.
val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)
Это незначительное удобство иногда имеет смысл. Обратите внимание, что функции не могут быть параметрическими, поэтому в некоторых случаях требуется метод.
Ваш второй пример - гибрид: метод раздела с одним параметром, который возвращает функцию.
Многоступенчатое вычисление
Где еще полезны каррированные функции? Вот шаблон, который возникает постоянно:
def v(t: Double, k: Double): Double = {
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!
}