He visto referencias a funciones curriculares en varios artículos y blogs, pero no puedo encontrar una buena explicación (¡o al menos una que tenga sentido!)
653
He visto referencias a funciones curriculares en varios artículos y blogs, pero no puedo encontrar una buena explicación (¡o al menos una que tenga sentido!)
curry
yuncurry
de Haskell. Lo importante aquí es que estos isomorfismos se arreglan de antemano y, por lo tanto, están "incorporados" en el lenguaje.add x y = x+y
(curry) es diferente aadd (x, y)=x+y
(sin curry)Respuestas:
Curry es cuando desglosas una función que toma múltiples argumentos en una serie de funciones que cada uno toma solo un argumento. Aquí hay un ejemplo en JavaScript:
Esta es una función que toma dos argumentos, a y b, y devuelve su suma. Ahora vamos a curry esta función:
Esta es una función que toma un argumento, a, y devuelve una función que toma otro argumento, b, y esa función devuelve su suma.
La primera instrucción devuelve 7, como la instrucción add (3, 4). La segunda declaración define una nueva función llamada add3 que agregará 3 a su argumento. Esto es lo que algunas personas pueden llamar un cierre. La tercera declaración usa la operación add3 para agregar 3 a 4, produciendo nuevamente 7 como resultado.
fuente
[1, 2, 3, 4, 5]
que desea multiplicar por un número arbitrario. En Haskell, puedo escribirmap (* 5) [1, 2, 3, 4, 5]
para multiplicar la lista completa por5
, y así generar la lista[5, 10, 15, 20, 25]
.map
debe ser una función que solo tome 1 argumento, un elemento de la lista. La multiplicación, como concepto matemático, es una operación binaria; Se necesitan 2 argumentos. Sin embargo, en Haskell*
es una función curry, similar a la segunda versión deadd
en esta respuesta. El resultado de(* 5)
es una función que toma un solo argumento y lo multiplica por 5, y que nos permite usarlo con el mapa.En un álgebra de funciones, tratar con funciones que toman múltiples argumentos (o un argumento equivalente que es una N-tupla) es algo poco elegante, pero, como lo demostró Moses Schönfinkel (e, independientemente, Haskell Curry), no es necesario: todo lo que necesita se necesitan funciones que tengan un argumento.
Entonces, ¿cómo lidias con algo que naturalmente expresarías como, por ejemplo
f(x,y)
,? Bueno, lo tomas como equivalente af(x)(y)
-f(x)
, llámalog
, es una función, y le aplicas esa funcióny
. En otras palabras, solo tiene funciones que toman un argumento, pero algunas de esas funciones devuelven otras funciones (que TAMBIÉN toman un argumento ;-).Como de costumbre, wikipedia tiene una buena entrada resumida sobre esto, con muchos consejos útiles (probablemente incluyendo algunos con respecto a sus idiomas favoritos ;-), así como un tratamiento matemático un poco más riguroso.
fuente
div :: Integral a => a -> a -> a
, ¿notas esas flechas múltiples? "Mapear una función mapeando a a" es una lectura ;-) Usted podría utilizar un (único) argumento para tupladiv
etc., pero eso sería muy anti-idiomática en Haskell.Aquí hay un ejemplo concreto:
Suponga que tiene una función que calcula la fuerza gravitacional que actúa sobre un objeto. Si no conoce la fórmula, puede encontrarla aquí . Esta función toma los tres parámetros necesarios como argumentos.
Ahora, estando en la tierra, solo quieres calcular las fuerzas de los objetos en este planeta. En un lenguaje funcional, podría pasar la masa de la tierra a la función y luego evaluarla parcialmente. Lo que obtendría es otra función que toma solo dos argumentos y calcula la fuerza gravitacional de los objetos en la tierra. Esto se llama curry.
fuente
El curry es una transformación que se puede aplicar a las funciones para permitirles tomar un argumento menos que antes.
Por ejemplo, en F # puede definir una función así: -
Aquí la función f toma los parámetros x, y y z y los suma de manera que: -
Devuelve 6.
A partir de nuestra definición, podemos definir la función de curry para f: -
Donde 'fun x -> fx' es una función lambda equivalente a x => f (x) en C #. Esta función ingresa la función que desea curry y devuelve una función que toma un solo argumento y devuelve la función especificada con el primer argumento establecido en el argumento de entrada.
Usando nuestro ejemplo anterior podemos obtener un curry de f así: -
Entonces podemos hacer lo siguiente: -
Lo que nos proporciona una función f1 que es equivalente a f1 yz = 1 + y + z. Esto significa que podemos hacer lo siguiente: -
Lo que devuelve 6.
Este proceso a menudo se confunde con la 'aplicación de función parcial' que se puede definir así:
Aunque podemos extenderlo a más de un parámetro, es decir: -
Una aplicación parcial tomará la función y los parámetros y devolverá una función que requiere uno o más parámetros, y como muestran los dos ejemplos anteriores, se implementa directamente en la definición de función F # estándar para que podamos lograr el resultado anterior así:
Lo que devolverá un resultado de 6.
En conclusión:-
La diferencia entre la aplicación de curry y la función parcial es que:
Curry toma una función y proporciona una nueva función que acepta un único argumento y devuelve la función especificada con su primer argumento establecido en ese argumento. Esto nos permite representar funciones con múltiples parámetros como una serie de funciones de argumento único . Ejemplo:-
La aplicación de función parcial es más directa: toma una función y uno o más argumentos y devuelve una función con los primeros n argumentos establecidos en los n argumentos especificados. Ejemplo:-
fuente
Puede ser una forma de usar funciones para hacer otras funciones.
En javascript:
Nos permitiría llamarlo así:
Cuando esto se ejecuta,
10
se pasa comox
;lo que significa que se nos devuelve esta función:
Entonces cuando llamas
realmente estás llamando:
Entonces, si haces esto:
es lo mismo que:
Entonces nuestro
addTen()
siempre agrega diez a lo que sea que pasemos. Podemos hacer funciones similares de la misma manera:Ahora la pregunta obvia de seguimiento es ¿por qué querrías hacer eso? Convierte lo que era una operación entusiasta
x + y
en una que se puede pasar perezosamente, lo que significa que podemos hacer al menos dos cosas: 1. operaciones costosas en caché 2. lograr abstracciones en el paradigma funcional.Imagina que nuestra función curry se ve así:
Podríamos llamar a esta función una vez, luego pasar el resultado para usarlo en muchos lugares, lo que significa que solo hacemos las cosas computacionalmente caras una vez:
Podemos obtener abstracciones de manera similar.
fuente
Una función currificada es una función de varios argumentos reescritos de tal manera que acepta el primer argumento y devuelve una función que acepta el segundo argumento y así sucesivamente. Esto permite que las funciones de varios argumentos tengan algunos de sus argumentos iniciales parcialmente aplicados.
fuente
map
una funciónf
sobre una lista de listasxss
, puede hacerlomap (map f) xss
.Aquí hay un ejemplo de juguete en Python:
(Simplemente usando la concatenación a través de + para evitar distracciones para los programadores que no son Python).
Edición para agregar:
Consulte http://docs.python.org/library/functools.html?highlight=partial#functools.partial , que también muestra la distinción de objeto parcial frente a función en la forma en que Python implementa esto.
fuente
Curry es traducir una función de invocable como
f(a, b, c)
a invocable comof(a)(b)(c)
.De lo contrario, curry es cuando desglosas una función que toma múltiples argumentos en una serie de funciones que forman parte de los argumentos.
Literalmente, el curry es una transformación de funciones: de una forma de llamar a otra. En JavaScript, generalmente hacemos un contenedor para mantener la función original.
El curry no llama a una función. Simplemente lo transforma.
Hagamos una función de curry que realice curry para funciones de dos argumentos. En otras palabras,
curry(f)
para dos argumentos sef(a, b)
traduce enf(a)(b)
Como puede ver, la implementación es una serie de envoltorios.
curry(func)
es una envolturafunction(a)
.sum(1)
, el argumento se guarda en el entorno léxico y se devuelve un nuevo contenedorfunction(b)
.sum(1)(2)
finalmente llamafunction(b)
proporcionando 2, y pasa la llamada a la suma original de múltiples argumentos.fuente
Si entiendes
partial
que estás a medio camino. La idea departial
es preaplicar argumentos a una función y devolver una nueva función que solo quiere los argumentos restantes. Cuando se llama a esta nueva función, incluye los argumentos precargados junto con los argumentos que se le proporcionaron.En Clojure
+
es una función pero para dejar las cosas muy claras:Puede saber que la
inc
función simplemente agrega 1 a cualquier número que se pase.Vamos a construirlo nosotros mismos usando
partial
:Aquí devolvemos otra función que tiene 1 cargado en el primer argumento de
add
. Comoadd
toma dos argumentos, la nuevainc
función solo quiere elb
argumento, no 2 argumentos como antes ya que 1 ya ha sido parcialmente aplicado . Porpartial
lo tanto, es una herramienta para crear nuevas funciones con los valores predeterminados presupuestados. Es por eso que en un lenguaje funcional las funciones a menudo ordenan argumentos de general a específico. Esto facilita la reutilización de tales funciones a partir de las cuales construir otras funciones.Ahora imagine si el lenguaje fuera lo suficientemente inteligente como para comprender introspectivamente que
add
quisiera dos argumentos. Cuando le pasamos un argumento, en lugar de rechazarlo, ¿qué pasa si la función aplica parcialmente el argumento lo pasamos en nuestro nombre entendiendo que probablemente teníamos la intención de proporcionar el otro argumento más tarde? Entonces podríamos definirinc
sin usar explícitamentepartial
.Así se comportan algunos idiomas. Es excepcionalmente útil cuando se desea componer funciones en transformaciones más grandes. Esto llevaría a uno a los transductores.
fuente
Encontré este artículo, y el artículo al que hace referencia, útil, para comprender mejor el curry: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
Como los otros mencionaron, es solo una forma de tener una función de un parámetro.
Esto es útil porque no tiene que asumir cuántos parámetros se pasarán, por lo que no necesita funciones de 2 parámetros, 3 parámetros y 4 parámetros.
fuente
Como todas las demás respuestas, curry ayuda a crear funciones parcialmente aplicadas. Javascript no proporciona soporte nativo para curry automático. Por lo tanto, los ejemplos proporcionados anteriormente pueden no ayudar en la codificación práctica. Hay un excelente ejemplo en Vivescript (que esencialmente compila a js) http://livescript.net/
En el ejemplo anterior, cuando ha dado menos argumentos sin, el script en vivo genera una nueva función curry para usted (doble)
fuente
Curry puede simplificar tu código. Esta es una de las principales razones para usar esto. El curry es un proceso de convertir una función que acepta n argumentos en n funciones que aceptan solo un argumento.
El principio es pasar los argumentos de la función pasada, utilizando la propiedad de cierre (cierre), para almacenarlos en otra función y tratarla como un valor de retorno, y estas funciones forman una cadena, y los argumentos finales se pasan para completar la operacion.
El beneficio de esto es que puede simplificar el procesamiento de parámetros al tratar un parámetro a la vez, lo que también puede mejorar la flexibilidad y la legibilidad del programa. Esto también hace que el programa sea más manejable. También dividir el código en partes más pequeñas lo haría fácil de reutilizar.
Por ejemplo:
También puedo hacer ...
Esto es muy bueno para hacer que el código complejo sea ordenado y manejar métodos no sincronizados, etc.
fuente
Una función curry se aplica a múltiples listas de argumentos, en lugar de solo una.
Aquí hay una función regular, no curry, que agrega dos parámetros Int, x e y:
Aquí hay una función similar que es curry. En lugar de una lista de dos parámetros Int, aplica esta función a dos listas de un parámetro Int cada una:
Lo que sucede aquí es que cuando invocas
curriedSum
, en realidad obtienes dos invocaciones de funciones tradicionales consecutivas. La invocación de la primera función toma un único parámetro Int llamadox
, y devuelve un valor de función para la segunda función. Esta segunda función toma el parámetro Inty
.Aquí hay una función llamada
first
que hace en espíritu locurriedSum
que haría la primera invocación de función tradicional :Aplicar 1 a la primera función, en otras palabras, invocar la primera función y pasar 1, produce la segunda función:
Aplicar 2 a la segunda función produce el resultado:
fuente
Un ejemplo de curry sería cuando tenga funciones que solo conoce uno de los parámetros en este momento:
Por ejemplo:
Aquí, dado que no conoce el segundo parámetro para la devolución de llamada al enviarlo,
performAsyncRequest(_:)
tendrá que crear otro lambda / cierre para enviarlo a la función.fuente
func callback
volviendo a sí mismo? Se llama @callback(str)
entonceslet callback = callback(str)
, la devolución de llamada es solo el valor de retorno defunc callback
func callback(_:data:)
acepta dos parámetros, aquí solo le doy uno, elString
, por lo que está esperando el siguiente (NSData
), esta es la razón por la cual ahoralet callback
hay otra función esperando que se pasen los datosAquí está el ejemplo de genérico y la versión más corta para la función de curry con n no. de params.
fuente
Aquí puede encontrar una explicación simple de la implementación del currículum en C #. En los comentarios, he intentado mostrar cómo curry puede ser útil:
fuente
El curry es una de las funciones de orden superior de Java Script.
El curry es una función de muchos argumentos que se reescribe de tal manera que toma el primer argumento y devuelve una función que a su vez usa los argumentos restantes y devuelve el valor.
¿Confuso?
Veamos un ejemplo,
Esto es similar a la siguiente función de curry,
Entonces, ¿qué significa este código?
Ahora lea la definición nuevamente,
El curry es una función de muchos argumentos que se reescribe de tal manera que toma el primer argumento y devuelve una función que a su vez usa los argumentos restantes y devuelve el valor.
¿Sigo confundido? Déjame explicarte en profundidad!
Cuando llamas a esta función,
Te devolverá una función como esta,
Entonces, esto se llama funciones de orden superior. Es decir, invocar una función por turnos devuelve otra función es una definición exacta para la función de orden superior. Esta es la mayor ventaja para la leyenda, Java Script. Así que vuelve al curry
Esta línea pasará el segundo argumento a la función curryAdd.
que a su vez resulta,
Espero que entiendas el uso de curry aquí. Entonces, llegando a las ventajas,
¿Por qué curry?
Hace uso de la reutilización del código. Menos código, menos error. ¿Puede preguntar cómo es menos código?
Puedo probarlo con las nuevas funciones de flecha de ECMA script 6.
¡Si! ECMA 6, nos proporciona la maravillosa característica llamada funciones de flecha,
Con la ayuda de la función de flecha, podemos escribir la función anterior de la siguiente manera,
¿Guay, verdad?
¡Entonces, menos código y menos errores!
Con la ayuda de estas funciones de orden superior, se puede desarrollar fácilmente un código libre de errores.
¡Te reto!
Espero que hayas entendido lo que es curry. No dude en comentar aquí si necesita alguna aclaración.
Gracias, que tengas un buen día!
fuente
Hay un ejemplo de "Curry en ReasonML".
fuente