Genau genommen ist dies keine Curry-Funktion, sondern eine Methode mit mehreren Argumentlisten, obwohl sie zugegebenermaßen wie eine Funktion aussieht.
Wie Sie sagten, ermöglichen die Listen mit mehreren Argumenten, dass die Methode anstelle einer teilweise angewendeten Funktion verwendet wird. (Entschuldigung für die allgemein albernen Beispiele, die ich benutze)
object NonCurr {
def tabulate[A](n: Int, fun: Int => A) = IndexedSeq.tabulate(n)(fun)
}
NonCurr.tabulate[Double](10, _)
val x = IndexedSeq.tabulate[Double](10) _
x(math.exp(_))
Ein weiterer Vorteil ist, dass Sie geschweifte Klammern anstelle von Klammern verwenden können, was gut aussieht, wenn die zweite Argumentliste aus einer einzelnen Funktion oder einem Thunk besteht. Z.B
NonCurr.tabulate(10, { i => val j = util.Random.nextInt(i + 1); i - i % 2 })
gegen
IndexedSeq.tabulate(10) { i =>
val j = util.Random.nextInt(i + 1)
i - i % 2
}
Oder für den Thunk:
IndexedSeq.fill(10) {
println("debug: operating the random number generator")
util.Random.nextInt(99)
}
Ein weiterer Vorteil ist, dass Sie zum Definieren von Standardargumentwerten auf Argumente einer vorherigen Argumentliste verweisen können (obwohl Sie auch sagen könnten, dass es ein Nachteil ist, dass Sie dies nicht in einer einzelnen Liste tun können :)
def doSomething(f: java.io.File)(modDate: Long = f.lastModified) = ???
Schließlich gibt es drei weitere Anwendungen in einer Antwort auf einen verwandten Beitrag. Warum bietet Scala sowohl mehrere Parameterlisten als auch mehrere Parameter pro Liste an? . Ich werde sie hier nur kopieren, aber der Kredit geht an Knut Arne Vedaa, Kevin Wright und extempore.
Erstens: Sie können mehrere var args haben:
def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum
... was in einer einzigen Argumentliste nicht möglich wäre.
Zweitens hilft es bei der Typinferenz:
def foo[T](a: T, b: T)(op: (T,T) => T) = op(a, b)
foo(1, 2){_ + _}
def foo2[T](a: T, b: T, op: (T,T) => T) = op(a, b)
foo2(1, 2, _ + _)
Und schließlich ist dies die einzige Möglichkeit, implizite und nicht implizite implicit
Argumente zu haben , ebenso wie ein Modifikator für eine ganze Argumentliste:
def gaga [A](x: A)(implicit mf: Manifest[A]) = ???
def gaga2[A](x: A, implicit mf: Manifest[A]) = ???
Es gibt noch einen weiteren Unterschied, der von der hervorragenden Antwort von 0 __ nicht abgedeckt wurde : Standardparameter. Ein Parameter aus einer Parameterliste kann verwendet werden, wenn der Standard in einer anderen Parameterliste berechnet wird, jedoch nicht in derselben.
Zum Beispiel:
def f(x: Int, y: Int = x * 2) = x + y // not valid def g(x: Int)(y: Int = x * 2) = x + y // valid
quelle
g(1)()
gibt 3.g(1)(2)
zurück 5. gibt 5. zurückDas ist der springende Punkt: Die Curry- und die Curry-Form sind gleichwertig! Wie andere bereits betont haben, kann es je nach Situation syntaktisch bequemer sein, mit der einen oder anderen Form zu arbeiten, und dies ist der einzige Grund, die eine der anderen vorzuziehen.
Es ist wichtig zu verstehen, dass Sie Scala auch dann erstellen können, wenn Sie keine spezielle Syntax zum Deklarieren von Curry-Funktionen haben. Dies ist nur eine mathematische Unvermeidlichkeit, wenn Sie Funktionen erstellen können, die Funktionen zurückgeben.
Um dies zu demonstrieren, stellen Sie sich vor, dass die
def foo(a)(b)(c) = {...}
Syntax nicht vorhanden war. Dann könnten Sie immer noch genau das Gleiche erreichen :def foo(a) = (b) => (c) => {...}
.Wie viele Funktionen in Scala ist dies nur eine syntaktische Annehmlichkeit, um etwas zu tun, das sowieso möglich wäre, aber mit etwas mehr Ausführlichkeit.
quelle
Die beiden Formen sind isomorph. Der Hauptunterschied besteht darin, dass Curry-Funktionen teilweise einfacher anzuwenden sind, während Nicht-Curry-Funktionen zumindest in Scala eine etwas schönere Syntax haben.
quelle