2011-09-02 25 views
9

Estoy tratando de comprender el objetivo de esta característica de lenguaje de varias cláusulas de parámetros y por qué la usaría. Por ejemplo, ¿cuál es la diferencia entre estas dos funciones realmente?¿Cuál es el sentido de las cláusulas de parámetros múltiples en las definiciones de funciones en Scala?

class WTF { 
    def TwoParamClauses(x : Int)(y: Int) = x + y 
    def OneParamClause(x: Int, y : Int) = x + y 
} 

>> val underTest = new WTF 
>> underTest.TwoParamClauses(1)(1) // result is '2' 
>> underTest.OneParamClause(1,1) // result is '2' 

Hay algo en esto en el Scala specification at point 4.6. Ve si eso tiene sentido para ti.

NB: la especificación llama a estas 'cláusulas de parámetros', pero creo que algunas personas también pueden llamarlas 'listas de parámetros'.

+0

programador Nnon-scala aquí. Tal vez es solo un estilo diferente? No todo tiene que tener solo una forma de hacerlo. – apscience

+0

bien, hay un poco de respuesta a esto en la respuesta de Daniel Sobral a http://stackoverflow.com/questions/4697404/scala-currying-by-nested-functions-or-by-multiple-parameter-lists –

+0

aceptado la respuesta aquí probablemente responda a esta pregunta: (1) para que no tenga que especificar el tipo de la primera cláusula param en la segunda cláusula; (2) para la flexibilidad del diseño de la biblioteca; (3) para facilitar el currado: http://stackoverflow.com/questions/4915027/two-ways-of-currying-in-scala-whats-the-use-case-for-each –

Respuesta

9

Aquí hay tres usos prácticos de múltiples listas de parámetros,

  1. para ayudar a la inferencia de tipos. Esto es especialmente útil cuando se usan métodos de orden superior. A continuación, el parámetro de tipo A de g2 se infiere de la primera parámetro x, por lo que los argumentos de la función en el segundo parámetro f pueden elided,

    def g1[A](x: A, f: A => A) = f(x) 
    g1(2, x => x) // error: missing parameter type for argument x 
    
    def g2[A](x: A)(f: A => A) = f(x) 
    g2(2) {x => x} // type is inferred; also, a nice syntax 
    
  2. Para los parámetros implícitos. Solo la última lista de parámetros puede marcarse como implícita, y una sola lista de parámetros no puede mezclar parámetros implícitos y no implícitos. La definición de g3 a continuación requiere dos listas de parámetros,

    // analogous to a context bound: g3[A : Ordering](x: A) 
    def g3[A](x: A)(implicit ev: Ordering[A]) {} 
    
  3. Para establecer los valores predeterminados basados ​​en los parámetros anteriores,

    def g4(x: Int, y: Int = 2*x) {} // error: not found value x 
    def g5(x: Int)(y: Int = 2*x) {} // OK 
    
3

Hay algunos casos en los que esta distinción es importante:

  1. listas de parámetros múltiples le permiten tener cosas como TwoParamClauses (2); que es una función generada automáticamente de tipo Int => Int que agrega 2 a su argumento. Por supuesto, usted mismo puede definir lo mismo usando OneParamClause, pero tomará más teclas

  2. Si tiene una función con parámetros implícitos que también tiene parámetros explícitos, los parámetros implícitos deben estar todos en su propia cláusula de parámetro (esto puede parecer una restricción arbitraria, pero en realidad es bastante sensato)

Aparte de eso, creo que la diferencia es estilística.

8

TwoParamClause implica dos invocaciones de método, mientras que OneParamClause invoca el método método una sola vez. Creo que el término que está buscando es currying. Entre los muchos casos de uso, le ayuda a dividir el cálculo en pequeños pasos. Este answer puede convencerlo de la utilidad del currying.

+1

El formulario con dos cláusulas de parámetros solo invoca el * método * una vez; el resultado de esa invocación es una * función * que luego se aplica, dando como resultado el valor final. –

+1

@pst: Pero aplicar una función también invoca un método (a saber, el método 'apply' de la función). –

+0

@Alexey Romanov Cierto. La redacción original del post era diferente ;-) En el comentario fechado, intentaba enfatizar la diferencia entre un método (algo que un objeto sabe cómo "responder") y una función (un objeto discreto que se puede aplicar, incluso si tal aplicación es el resultado de invocar un método sobre ella). También estoy en desacuerdo con la terminología "...invoca la función solo una vez "porque invoca el método' OneParamClause' * * solo una vez. –

4

listas de parámetros múltiples pueden ayudar tipo Scala inferencia para más detalles ver: Making the most of Scala's (extremely limited) type inference

tipo de información no fluye de izquierda a derecha dentro una lista de argumentos, sólo de izquierda a derecha en listas de argumentos. Entonces, aunque Scala conoce los tipos de los primeros dos argumentos ... esa información no fluye a nuestra función anónima.

...

Ahora que nuestra función binaria está en una lista de argumentos separados, cualquier información de tipo del listas de argumentos anteriores se utiliza para rellenar los tipos de nuestra función ... por lo tanto, no es necesario anotar los parámetros de nuestra lambda.

+0

Asegúrese de incluir extractos y/o razonamientos y no solo enlaces desnudos en las publicaciones. Una muy buena búsqueda de artículos, sin embargo, –

+0

pensé que mi breve descripción sería suficiente para provocar y, para una referencia completa, uno debería leer el blog. Pero así está bien también :) – AndreasScheinert

6

Existe una diferencia entre ambas versiones con respecto a la inferencia de tipo.Considere

def f[A](a:A, aa:A) = null 
f("x",1) 
//Null = null 

En este caso, el tipo A está obligado a Any, que es un tipo súper de String y Int. Pero:

def g[A](a:A)(aa:A) = null 
g("x")(1) 

error: type mismatch; 
found : Int(1) 
required: java.lang.String 
     g("x")(1) 
      ^

Como se ve, el tipo de corrector sólo se considera la primera lista de argumentos, por lo A consigue obligado a String, por lo que el valor de Intaa en la segunda lista de argumentos es un error de tipo.

Cuestiones relacionadas