Methoden mit mehreren Parameterlisten
Für Typinferenz
Methoden mit mehreren Parameterabschnitten können verwendet werden, um die lokale Typinferenz zu unterstützen, indem Parameter im ersten Abschnitt verwendet werden, um Typargumente abzuleiten, die im nachfolgenden Abschnitt einen erwarteten Typ für ein Argument bereitstellen. foldLeft
in der Standardbibliothek ist das kanonische Beispiel dafür.
def foldLeft[B](z: B)(op: (B, A) => B): B
List("").foldLeft(0)(_ + _.length)
Wenn dies so geschrieben wäre als:
def foldLeft[B](z: B, op: (B, A) => B): B
Man müsste explizitere Typen angeben:
List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)
Für fließende API
Eine andere Verwendung für Methoden mit mehreren Parameterabschnitten besteht darin, eine API zu erstellen, die wie ein Sprachkonstrukt aussieht. Der Anrufer kann anstelle von Klammern geschweifte Klammern verwenden.
def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)
loop(2) {
println("hello!")
}
Die Anwendung von N Argumentlisten auf Methoden mit M Parameterabschnitten, wobei N <M ist, kann explizit mit einem _
oder implizit mit einem erwarteten Typ von in eine Funktion konvertiert werden FunctionN[..]
. Dies ist eine Sicherheitsfunktion. Hintergrundinformationen finden Sie in den Änderungshinweisen für Scala 2.0 in den Scala-Referenzen.
Curry-Funktionen
Curry-Funktionen (oder einfach Funktionen, die Funktionen zurückgeben) lassen sich leichter auf N Argumentlisten anwenden.
val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)
Diese kleine Bequemlichkeit lohnt sich manchmal. Beachten Sie, dass Funktionen nicht typparametrisch sein können. In einigen Fällen ist daher eine Methode erforderlich.
Ihr zweites Beispiel ist ein Hybrid: eine Ein-Parameter-Abschnittsmethode, die eine Funktion zurückgibt.
Mehrstufige Berechnung
Wo sonst sind Curry-Funktionen nützlich? Hier ist ein Muster, das ständig auftaucht:
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);
Wie können wir das Ergebnis teilen f(t)
? Eine übliche Lösung besteht darin, eine vektorisierte Version von v
:
def v(t: Double, ks: Seq[Double]: Seq[Double] = {
val ft = f(t)
ks map {k => g(ft, k)}
}
Hässlich! Wir haben nicht verwandte Bedenken verwickelt - Berechnung g(f(t), k)
und Abbildung über eine Folge von 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))
Wir könnten auch eine Methode verwenden, die eine Funktion zurückgibt. In diesem Fall ist es etwas besser lesbar:
def v(t:Double): Double => Double = {
val ft = f(t)
(k: Double) => g(ft, k)
}
Wenn wir jedoch versuchen, dasselbe mit einer Methode mit mehreren Parameterabschnitten zu tun, bleiben wir stecken:
def v(t: Double)(k: Double): Double = {
^
`-- Can't insert computation here!
}