Estrictamente hablando, esta no es una función curry, sino un método con múltiples listas de argumentos, aunque ciertamente parece una función.
Como dijiste, las listas de argumentos múltiples permiten que el método se use en lugar de una función aplicada parcialmente. (Perdón por los ejemplos generalmente tontos que uso)
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(_))
Otro beneficio es que puede usar llaves en lugar de paréntesis, lo que se ve bien si la segunda lista de argumentos consiste en una sola función o procesador. P.ej
NonCurr.tabulate(10, { i => val j = util.Random.nextInt(i + 1); i - i % 2 })
versus
IndexedSeq.tabulate(10) { i =>
val j = util.Random.nextInt(i + 1)
i - i % 2
}
O para el thunk:
IndexedSeq.fill(10) {
println("debug: operating the random number generator")
util.Random.nextInt(99)
}
Otra ventaja es que puede consultar los argumentos de una lista de argumentos anterior para definir valores de argumento predeterminados (aunque también podría decir que es una desventaja que no puede hacer eso en una lista única :)
def doSomething(f: java.io.File)(modDate: Long = f.lastModified) = ???
Finalmente, hay otras tres aplicaciones en una respuesta a una publicación relacionada. ¿Por qué Scala proporciona listas de parámetros múltiples y parámetros múltiples por lista? . Los copiaré aquí, pero el mérito es de Knut Arne Vedaa, Kevin Wright y extempore.
Primero: puede tener varios argumentos var:
def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum
... que no sería posible en una sola lista de argumentos.
En segundo lugar, ayuda a la inferencia de tipos:
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, _ + _)
Y por último, esta es la única forma en que puede tener implicit
argumentos implícitos y no implícitos, al igual que un modificador para una lista completa de argumentos:
def gaga [A](x: A)(implicit mf: Manifest[A]) = ???
def gaga2[A](x: A, implicit mf: Manifest[A]) = ???
Hay otra diferencia que no fue cubierta por la excelente respuesta de 0 __ : los parámetros predeterminados. Se puede utilizar un parámetro de una lista de parámetros al calcular el valor predeterminado en otra lista de parámetros, pero no en la misma.
Por ejemplo:
def f(x: Int, y: Int = x * 2) = x + y // not valid def g(x: Int)(y: Int = x * 2) = x + y // valid
fuente
g(1)()
devuelve 3.g(1)(2)
devuelve 5.¡Ese es el punto, es que las formas con curry y sin curry son equivalentes! Como han señalado otros, una u otra forma puede ser sintácticamente más conveniente para trabajar dependiendo de la situación, y esa es la única razón para preferir una sobre la otra.
Es importante entender que incluso si Scala no tuviera una sintaxis especial para declarar funciones curry, aún podría construirlas; esto es solo una inevitabilidad matemática una vez que tenga la capacidad de crear funciones que devuelvan funciones.
Para demostrar esto, imagine que la
def foo(a)(b)(c) = {...}
sintaxis no existe. Entonces todavía se podía lograr exactamente lo mismo de esta manera:def foo(a) = (b) => (c) => {...}
.Como muchas funciones en Scala, esto es solo una conveniencia sintáctica para hacer algo que sería posible de todos modos, pero con un poco más de verbosidad.
fuente
Las dos formas son isomorfas. La principal diferencia es que las funciones con curry son más fáciles de aplicar parcialmente, mientras que las funciones sin curry tienen una sintaxis un poco más agradable, al menos en Scala.
fuente