Pregunta ¿Por qué Scala proporciona listas de parámetros múltiples y múltiples parámetros por lista? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Múltiples listas de parámetros, p. def foo(a:Int)(b:Int) = {} y múltiples parámetros por lista, p. def foo(a:Int, b:Int) = {} son semánticamente equivalentes por lo que puedo decir, y la mayoría de los lenguajes funcionales tienen una sola forma de declarar múltiples parámetros, p. F#.

La única razón por la que puedo deducir que admite estos dos estilos de definiciones de función es permitir extensiones de lenguaje similares a la sintaxis utilizando una lista de parámetros que solo tiene un parámetro.

def withBufferedWriter(file: File)(block: BufferedWriter => Unit)

ahora se puede llamar con el aspecto sintáctico

withBufferedWriter(new File("myfile.txt")) { out =>
  out write "whatever"
  ...
}

Sin embargo, podría haber otras formas de apoyar el uso de llaves sin tener múltiples listas de parámetros.

Una pregunta relacionada: ¿por qué el uso de listas de parámetros múltiples en Scala se llama "currying"? El currying generalmente se define como una técnica para hacer que una función n-ary sea unitaria por el solo hecho de soportar una aplicación parcial. Sin embargo, en Scala se puede aplicar parcialmente una función sin hacer una versión "curried" (listas de parámetros múltiples con un param cada) de la función.


75
2018-01-13 19:12


origen


Respuestas:


Te hace capaz de hacer, p. Ej .:

scala> def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum
foo: (as: Int*)(bs: Int*)(cs: Int*)Int

scala> foo(1, 2, 3)(4, 5, 6, 7, 9)(10, 11)
res7: Int = 3906

76
2018-01-13 19:55



Además de permitirle escribir métodos que se ven como parte del lenguaje (que ya vio), vale la pena señalar que el tipo inferencer funcionará con un bloque a la vez.

Entonces en esto:

def foo[T](a: T, b: T)(op: (T,T)=>T) = op(a,b)
foo(1,2){_+_}

T primero será inferido como Int, que luego se usará como el tipo de los dos guiones bajos en el cierre. Así es como el compilador sabe, con seguridad de tipo completo, que la operación + es válida.


45
2018-01-14 00:36



Para responder a su "pregunta relacionada", currying es simplemente una forma de convertir una función de múltiples argumentos, por ejemplo (A, B, C) => D, en una función que toma un argumento y devuelve una función, p. A => (B => (C => D)) (paréntesis mostrados pero no necesarios).

La forma tuple -ized y la forma curried son isomorfas, y podemos traducir libremente entre ellas. Todos estos son equivalentes, pero tienen diferentes implicaciones sintácticas:

(A, B, C, D, E) => F
((A, B), (C, D, E)) => F
(A, B) => (C, D, E) => F

Cuando declaras grupos de parámetros separados, este es el tipo de currying que estás haciendo. El método de grupo de parámetros múltiples es un método que devuelve una función ... puede ver esto en REPL:

scala> def foo(a:Int, b:Int)(c:Int, d:Int, e:Int):Int = 9
foo: (a: Int,b: Int)(c: Int,d: Int,e: Int)Int

scala> foo _                                             
res4: (Int, Int) => (Int, Int, Int) => Int = <function2>

24
2018-01-13 21:36



Referencias traseras en argumentos por defecto:

case class Foo(bar: Int)

def test(f: Foo)(i: Int = f.bar) = i*i

test(Foo(3))()

20
2018-02-27 20:22



Sé que una de las motivaciones fue la lista de parámetros implícitos. "implícito" es una propiedad de la lista, no del parámetro. Otra era probablemente las clases de casos: solo la primera lista de parámetros se convertía en campos de casos.


12
2018-01-14 05:36