Кілька методів списку параметрів
Для виведення типу
Методи з декількома розділами параметрів можуть бути використані для сприяння виводу локального типу, використовуючи параметри в першому розділі для виведення аргументів типу, які нададуть очікуваний тип для аргументу в наступному розділі. 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 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!
}