scala currying

scala - ¿Cuál es la diferencia entre curry y múltiples listas de parámetros?



currying (1)

Espero que no te importe si comienzo con un ejemplo de Haskell, ya que Haskell es un lenguaje mucho más simple que Scala. En Haskell, todas las funciones son funciones en el sentido matemático: toman un argumento y devuelven un valor. Haskell también tiene tuplas, y puede escribir una función que parezca que toma múltiples parámetros, como una función de una tupla a lo que sea. Por ejemplo:

Prelude> let add = (/(x, y) -> x + y) :: (Int, Int) -> Int Prelude> add (1, 2) 3

Ahora podemos utilizar esta función para obtener una función con el tipo Int -> Int -> Int lugar de (Int, Int) -> Int :

Prelude> let curriedAdd = curry add

Esto nos permite aplicar parcialmente la función, por ejemplo:

Prelude> let add3 = curriedAdd 3 Prelude> add3 1 4

Así que tenemos una buena definición de curry: es una función que toma una función con una tupla (específicamente un par) para un argumento y devuelve una función que toma como argumento el primer tipo del par y devuelve una función del segundo escriba en el par al tipo de retorno original. Que es solo una manera prolija de decir esto:

Prelude> :t curry curry :: ((a, b) -> c) -> a -> b -> c

Bien, ahora para Scala.

En Scala también puede tener funciones que toman un argumento de tupla. Scala también tiene "funciones" que toman más de un argumento ( Function2 y superior). Estos son (confusamente) diferentes tipos de animales.

Scala también tiene métodos, que son diferentes de las funciones (aunque se pueden convertir en funciones de forma más o menos automática a través de la expansión eta ). Los métodos pueden tener múltiples parámetros, o parámetros de tupla, o múltiples listas de parámetros.

Entonces, ¿qué significa decir que estamos estudiando algo en este contexto?

Literalmente, el curry es algo que haces con una Function2 (y más):

scala> val add: Function2[Int, Int, Int] = (x: Int, y: Int) => x + y add: (Int, Int) => Int = <function2> scala> val curriedAdd = add.curried curriedAdd: Int => (Int => Int) = <function1> scala> val add3 = curriedAdd(3) add3: Int => Int = <function1>

Esto es casi igual a lo que vimos en el caso de Haskell, excepto que estamos desarrollando una función con múltiples argumentos, que es algo que no existe correctamente en Haskell.

Ahora estoy bastante seguro de que este es el único contexto en el que la palabra curry aparece en realidad en la biblioteca estándar de Scala (sin contar el uncurried de Function uncurried acompañado ), pero dado el enorme lío que Scala hace de la idea de los métodos, funciones, etc. (no me malinterpretes, amo a Scala, pero esta parte del lenguaje es un completo desastre), me parece bastante razonable aplicar la palabra en el siguiente contexto también:

def add(x: Int, y: Int) = x + y def curriedAdd(x: Int)(y: Int) = add(x, y)

Aquí hemos convertido un método que toma dos parámetros en un método con múltiples listas de parámetros, cada uno de los cuales solo toma un único parámetro (esta última parte es importante).

Y, de hecho, la especificación del lenguaje también usa el término en este contexto, describiendo lo siguiente como "una definición de función única y con currículum":

def func(x: Int) (y: Int) = x + y

(Lo que por supuesto es confuso como el infierno, ya que este es un método, no una función).

Para resumir: las listas de múltiples parámetros son una forma de implementar el curry en Scala, pero no todos los métodos con listas de múltiples parámetros tienen un curry, solo unos donde cada lista de parámetros tiene un solo parámetro. Y de todos modos, toda la terminología es bastante blanda, así que no te preocupes demasiado por hacerlo bien.

Por todas partes que veo, veo los términos listas de parámetros múltiples y el uso del curry se usan de manera intercambiable. Lo veo en docenas de preguntas de stackoverflow, e incluso en scala-lang.org. Esta página , por ejemplo, tiene el título "Currying". ¿Y la primera frase? "Los métodos pueden definir múltiples listas de parámetros".

Y, sin embargo, algunas personas muy informadas se molestan cuando ven múltiples listas de parámetros y el curry igualado. Publiqué una respuesta a esta pregunta, pero luego la borré cuando vi el comentario de Randall Schulz porque temía que pudiera estar difundiendo inadvertidamente información errónea. Entendí que una función con múltiples listas de parámetros es necesariamente una función de curry, pero esa función se puede lograr también de otras maneras (la respuesta principal a esta pregunta enumera cuatro formas), pero no estoy seguro de que esa sea toda la historia . Quiero entender realmente la distinción.

Sé que hay muchas preguntas muy similares a esta en stackoverflow, pero no he encontrado una que explique precisamente la diferencia. ¿Qué necesito entender sobre las listas de parámetros múltiples y el curry para hablar con precisión sobre ellos?