javascript - ¿Qué es el curry?

CorePress2024-01-25  11

He visto referencias a funciones de curry en varios artículos y blogs, pero no encuentro una buena explicación (¡o al menos una que tenga sentido!)



------------------------------------

Currying es cuando se divide una función que toma múltiples argumentos en una serie de funciones que toman cada una solo un argumento. Aquí hay un ejemplo en JavaScript:

function add (a, b) {
  return a + b;
}

add(3, 4); // returns 7

Esta es una función que toma dos argumentos, a y b, y devuelve su suma. Ahora aplicaremos esta función:

function add (a) {
  return function (b) {
    return a + b;
  }
}

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.

add(3)(4); // returns 7

var add3 = add(3); // returns a function

add3(4); // returns 7
La primera declaración devuelve 7, como la declaración add(3, 4). La segunda declaración define una nueva función llamada add3 que agregue 3 a su argumento. (Esto es lo que algunos podrían llamar un cierre). La tercera declaración usa la operación add3 para sumar 3 a 4, nuevamente produciendo 7 como resultado. Respondido

30 de agosto de 2008 a las 20:19

Kyle Cronin

Kyle Cronin

78,1k

45

45 insignias de oro

148

148 insignias de plata

164

164 de bronce insignias

18

322

En un sentido práctico, ¿cómo puedo hacer uso de este concepto?

- Fresa

8 agosto 2013 a las 18:00

61

@Strawberry, digamos, por ejemplo, que tiene una lista de números en [1, 2, 3, 4, 5] que desea multiplicar por un número arbitrario. En Haskell, puedo escribir map (* 5) [1, 2, 3, 4, 5] para multiplicar toda la lista por 5 y generar así la lista [5, 10, 15, 20, 25].

-nyson

26/10/2013 a las 16:52

88

Entiendo lo que hace la función de mapa, pero no estoy seguro de entender el punto que intentas ilustrarme. ¿Estás diciendo que la función de mapa representa el concepto de curry?

- Fresa

26/10/2013 a las 23:11

101

@Strawberry La fEl primer argumento a mapear debe ser una función que tome solo 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 * hay una función curry, similar a la segunda versión de add en esta respuesta. El resultado de (* 5) es una función que toma un único argumento y lo multiplica por 5, y que nos permite usarlo con map.

- Doval

17/01/2014 a las 15:22

38

@Strawberry Lo bueno de los lenguajes funcionales como Standard ML o Haskell es que puedes obtenercurry "gratis". Puede definir una función de múltiples argumentos como lo haría en cualquier otro idioma, y ​​automáticamente obtendrá una versión curry de la misma, sin tener que agregar un montón de lambdas usted mismo. Por lo tanto, puede producir nuevas funciones que tomen menos argumentos de cualquier función existente sin mucho problema, y ​​eso facilita pasarlas a otras funciones.

- Doval

17/01/2014 a las 15:25



------------------------------------

En un álgebra de funciones, tratar con funciones que toman múltiples argumentos (o un argumento equivalente que sea una N-tupla) es algo poco elegante, pero, como dice Moses Schönfinkel (e, independientemente(Haskell Curry) demostró que no es necesario: todo lo que necesitas son funciones que tomen un argumento.

Entonces, ¿cómo manejas algo que naturalmente expresarías como, digamos, f(x,y)? Bueno, tomas eso como equivalente a f(x)(y) - f(x), llámalo g, es una función, y aplicas esa función a y. En otras palabras, solo tienes funciones que toman un argumento, pero algunas de esas funciones devuelven otras funciones (que TAMBIÉN toman un argumento ;-).

Como siempre, Wikipedia tiene una buena entrada resumida sobre esto, con muchos consejos útiles (probablemente incluidos algunos relacionados con tus idiomas favoritos;-), así como un tratamiento matemático ligeramente más riguroso.

6

1

Supongo que un comentario similar al mío anterior: no he visto que los lenguajes funcionales restrinjan las funciones a tomar un solo argumento. ¿Me equivoco?

usuario140327

30/08/2009 a las 21:50

1

@hoohoo: Los lenguajes funcionales generalmente no restringen las funciones a un solo argumento. Sin embargo, en un nivel inferior, más matemático, es mucho más fácil tratar con funciones que enSólo tome un argumento. (En el cálculo lambda, por ejemplo, las funciones solo toman un argumento a la vez).

- Sam DeFabbia-Kane

30/08/2009 a las 23:00

1

Está bien. Otra pregunta entonces. ¿Es verdadera la siguiente afirmación? El cálculo lambda se puede utilizar como modelo de programación funcional, pero la programación funcional no es necesariamente cálculo lambda aplicado.

usuario140327

31/08/2009 a las 14:59

8

Como señalan las páginas de Wikipedia, la mayoría de los lenguajes FP "embellecen" o "aumentar" cálculo lambda (por ejemplo, con algunas constantes y tipos de datos) en lugar de simplemente "aplicar" eso, pero no está tan cerca. Por cierto, ¿qué te da la impresión de que, p. ¿Haskell NO "restringe las funciones a tomar un solo argumento"? Seguro que sí, aunque eso es irrelevante gracias al curry; p.ej. div :: Integral a => un -> un -> a - ¿notas esas múltiples flechas? "Asignar una función asignando a a a" es una lectura ;-). Podrías usar un argumento de tupla (único) para div &c, pero eso sería realmente antiidiomático en Haskell.

- Alex Martelli

31/08/2009 a las 15:20

@Alex - con Haskell & arg count, no he dedicado mucho tiempo a Haskell, y eso fue hace unas semanas. Así que fue un error fácil de cometer.

usuario140327

31/08/2009 a las 17:03



------------------------------------

Aquí hay un ejemplo concreto:

Suponga que tiene una función que calcula la fuerza gravitacional que actúa sobre un objeto. Si no conoces la fórmula, puedes encontrarla aquí. Esta función toma enlos tres parámetros necesarios como argumentos.

Ahora, al estar en la Tierra, solo quieres calcular las fuerzas de los objetos en este planeta. En un lenguaje funcional, podrías pasar la masa de la Tierra a la función y luego evaluarla parcialmente. Lo que obtendrías es otra función que toma sólo dos argumentos y calcula la fuerza gravitacional de los objetos en la Tierra. Esto se llama curry.

6

3

Como curiosidad, la biblioteca Prototype para JavaScript ofrece una opción "curry"función que hace prácticamente exactamente lo que has explicado aquí: prototipojs.org/api/function/curry

- shuckster

30 de agosto de 2009 a las 2:26

Nuevo enlace de función curry de PrototypeJS. prototipojs.org/doc/latest/language/Function/prototype/curry/…

-Richard Ayotte

12/12/2012 a las 16:53

11

Esto suena parcial.aplicación para mí. Tengo entendido que si aplica curry, puede crear funciones con un solo argumento y componerlas para formar funciones más complicadas. ¿Me estoy perdiendo algo?

- neontapir

1 de abril de 2013 a las 21:48

12

@neontapir tiene razón. Lo que Shea describió no es curry. Es una aplicación parcial. Si se curtea una función de tres argumentos y la llamas como f(1), lo que obtienes no es una función de dos argumentos. Obtiene una función de un argumento que devuelve otra función de un argumento. Una función al curry sólo puedealguna vez se le pasará un argumento. La función curry en PrototypeJS tampoco es curry. Es una aplicación parcial.

- MindJuice

28 de octubre de 2015 a las 5:31

no (a evaluación parcial) y no (al curry). esto se conoce como aplicación parcial. se necesita curry para habilitarlo.

- Will Ness

22/08/2018 a las 13:29

------------------------------

Puede ser una forma de utilizar funciones para crear otras funciones.

En javascript:

let add = function(x){
  return function(y){ 
   return x + y
  };
};

Nos permitiría llamarlo así:

let addTen = add(10);

Cuando esto se ejecuta, el 10 se pasa como x;

let add = function(10){
  return function(y){
    return 10 + y 
  };
};

lo que significa que se nos devuelve esta función:

function(y) { return 10 + y };

Así que cuando llames

 addTen();

realmente estás llamando:

 function(y) { return 10 + y };

Entonces, si haces esto:

 addTen(4)

es lo mismo que:

function(4) { return 10 + 4} // 14

Así que nuestro addTen() siempre suma diez a todo lo que le pasamos. Podemos crear funciones similares de la misma manera:

let addTwo = add(2)       // addTwo(); will add two to whatever you pass in
let addSeventy = add(70)  // ... and so on...

Ahora la siguiente pregunta obvia es ¿por qué querrías hacer eso? Convierte lo que era una operación ansiosa x + y en una que se puede realizar con pereza, lo que significa que podemos hacer al menos dos cosas. 1. caché de operaciones costosas 2. lograrCinco abstracciones en el paradigma funcional.

Imagínese que nuestra función de curry se viera así:

let doTheHardStuff = function(x) {
  let z = doSomethingComputationallyExpensive(x)
  return function (y){
    z + y
  }
}

Podríamos llamar a esta función una vez y luego pasar el resultado para usarlo en muchos lugares, lo que significa que solo hacemos las cosas computacionalmente costosas una vez:

let finishTheJob = doTheHardStuff(10)
finishTheJob(20)
finishTheJob(30)

Podemos obtener abstracciones de forma similar.

7

26

La mejor explicación paso a paso de un proceso inherentemente secuencial que he visto aquí, y quizás la mejor y más explicativa respuesta de todas.

usuario7125259

16/03/2018 a las 7:02

7

@jonsilver Yo diría lo contrario, no es una buena explicación. Estoy de acuerdo en que es bueno para explicar el ejemplo planteado, pero la gente tiende a pensar: "Sí, perfectamente claro, pero podría haber hecho lo mismo de otra manera, entonces, ¿de qué sirve el curry?". En otras palabras, desearía que tuviera suficiente contexto o explicación para iluminar no solo cómo funciona el curry, sino también por qué no es una observación inútil y trivial en comparación con otras formas de sumar diez.

- Whitneyland

18/04/2018 a las 23:46

5

La pregunta original era "qué es", no por qué es útil.

- Adzz

26 de junio de 2020 a las 9:18

4

El patrón curry es una forma de aplicar un argumento fijo a una función existente con el fin de crear una nueva función reutilizable sin recrear la función original. Esta respuesta hace un excelente trabajo of demostrando eso.

-tobius

22/02/2021 a las 16:19

4

"Podemos hacer al menos dos cosas: 1. almacenar en caché operaciones costosas 2. lograr abstracciones en el paradigma funcional." Este es el "por qué es útil" explicación faltaban otras respuestas. Y creo que esta respuesta explicó el "qué" excelente también.

 drkvogel

10 de abril de 2021 a las 21:26



------------------------------------

El curry es una transformación que se puede aplicar a funciones para permitirles tomar un argumento menos que antes.

Por ejemplo, en F# puedes definir una función así:-

let f x y z = x + y + z

Aquí la función f toma los parámetros x, y y z y los suma de modo que:-

f 1 2 3

Devuelve 6.

A partir de nuestra definición podemos definir la función curry para f:-

let curry f = fun x -> f x

Donde 'fun x -> f x' es una función lambda equivalente a x => f(x) en C#. Esta función ingresa la función que desea currar 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.

Utilizando nuestro ejemplo anterior podemos obtener un curry de f así:-

let curryf = curry f

Entonces podemos hacer lo siguiente:-

let f1 = curryf 1

Lo que nos proporciona una función f1 que es equivalente a f1 y z = 1 + y + z. Esto significa que podemos hacer lo siguiente:-

f1 2 3

Que devuelve 6.

Este proceso a menudo se confunde con la 'aplicación de función parcial' que se puede definir así:-

let papply f x = f x

Aunque podemos extenderlo a más de un parámetro, es decir:-

let papply2 f x y = f x y
let papply3 f x y z = f x y z
etc.

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 menos y, como muestran los dos ejemplos anteriores, se implementa directamente en la definición de función estándar de F# para que podamos lograr el resultado anterior. así:-

let f1 = f 1
f1 2 3

Lo cual devolverá un resultado de 6.

En conclusión:-

La diferencia entre curry y aplicación de función parcial es que:-

Currying toma una función y proporciona una nueva función que acepta un solo 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 un solo argumento. Ejemplo:-

let f x y z = x + y + z
let curryf = curry f
let f1 = curryf 1
let f2 = curryf 2
f1 2 3
6
f2 1 3
6

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:-

let f x y z = x + y + z
let f1 = f 1
let f2 = f 2
f1 2 3
6
f2 1 3
6
Respondido al

30 de agosto de 2008 a las 21:06

ljs

ljs

37,5k

36

36 insignias de oro

106

106 insignias de plata

124

124 insignias de bronce

2

Entonces, ¿los métodos en C# deberían modificarse antes de poder aplicarse parcialmente?

- CDMCKAY

25 de julio de 2012 a las 1:43

"Esto nos permite representar funciones con múltiples parámetros como una serie de funciones de un solo argumento" - Educación físicaPerfecto, eso me aclaró todo muy bien. Gracias

Análisis difuso

13/09/2014 a las 22:36



------------------------------------

Una función curry es una función de varios argumentos reescritos de manera que acepta el primer argumento y devuelve una función que acepta el segundo argumento y así sucesivamente. Esto permite que funciones de varios argumentos tengan algunos de sus argumentos iniciales parcialmente aplicados.

4

7

"Esto permite que funciones de varios argumentos tengan algunos de sus argumentos iniciales parcialmente aplicados." - ¿Por qué es eso beneficioso?

-acarlon

4 de septiembre de 2013 a las 23:19

7

@acarlon Las funciones a menudo se llaman repetidamente con uno o más argumentos iguales. Por ejemplo, si desea asignar una función f sobre una lista de listas xss, puede hacerlo map (map f) xss.

- JD

5 de septiembre de 2013 a las 10:32

1

Gracias, eso tiene sentido. Leí un poco más y encajó.

-acarlon

5 de septiembre de 2013 a las 11:24

5

Creo que esta respuesta es correcta y concisa. El "curry" es el proceso de tomar la función de múltiples argumentos y convertirla en una serie de funciones, cada una de las cuales toma un solo argumento y devuelve una función de un solo argumento.nt, o en el caso de la función final, devolver el resultado real. Esto lo puede hacer automáticamente el idioma o puede llamar a una función curry() en otros idiomas para generar la versión con curry. Tenga en cuenta que llamar a una función curry con un parámetro no es curry. El curry ya pasó.

- MindJuice

28 de octubre de 2015 a las 5:48



------------------------------------

Currying significa convertir una función de N aridad en N funciones de aridad 1. La aridad de la función es el número de argumentos que requiere.

Aquí está la definición formal:

 curry(f) :: (a,b,c) -> f(a) -> f(b)-> f(c)

Aquí hay un ejemplo del mundo real que tiene sentido:

YoVas al cajero automático para sacar algo de dinero. Desliza su tarjeta, ingresa el número PIN y realiza su selección y luego presiona Enter para enviar el "monto" junto con la solicitud.

Aquí está la función normal para retirar dinero.

const withdraw=(cardInfo,pinNumber,request){
    // process it
       return request.amount
}

En esta implementación, la función espera que ingresemos todos los argumentos a la vez. Íbamos a deslizar la tarjeta, ingresar el PIN y realizar la solicitud, luego se ejecutaría la función. Si alguno de esos pasos tuvo problemas, lo descubrirá después de ingresar todos los argumentos. Con la función curry crearíamos funciones de mayor aridad, puras y simples. Las funciones puras nos ayudarán a depurar fácilmente nuestro código.

este es un cajero automático con función de curry:

const withdraw=(cardInfo)=>(pinNumber)=>(request)=>request.amount

ATM, toma la tarjeta como entrada y devuelve una función que espera pinNumber y esta función devuelve una función tHat acepta el objeto de solicitud y luego del proceso exitoso, obtienes la cantidad que solicitaste. En cada paso, si tuvo un error, podrá predecir fácilmente qué salió mal. Digamos que ingresa la tarjeta y obtiene un error, sabe que está relacionado con la tarjeta o la máquina, pero no con el número PIN. O si ingresó el PIN y no es aceptado, sabrá que ingresó mal el número de PIN. Depurarás fácilmente el error.

Además, cada función aquí es reutilizable, por lo que puedes usar las mismas funciones en diferentes partes de tu proyecto.



------------------------------------

Currying es traduccióng una función de invocable como f(a, b, c) a invocable como f(a)(b)(c).

De lo contrario, el curry es cuando se divide una función que toma múltiples argumentos en una serie de funciones que forman parte de los argumentos.

Literalmente, curry es una transformación de funciones: de una forma de llamar a otra. En JavaScript, normalmente creamos un contenedor para mantener la función original.

El curry no llama a una función. Simplemente lo transforma.

Creemos una función curry que realice curry para funciones de dos argumentos. En otras palabras, curry(f) para f(a, b) de dos argumentos lo traduce a f(a)(b)

function curry(f) { // curry(f) does the currying transform
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// usage
function sum(a, b) {
  return a + b;
}

let carriedSum = curry(sum);

alert( carriedSum(1)(2) ); // 3

Como puede ver, la implementación es una serie de envoltorios.

El resultado de curry(func) es una función contenedora(a). Cuando se llama como suma (1), el argumentose guarda en el entorno léxico y se devuelve un nuevo contenedor función (b). Luego, sum(1)(2) finalmente llama a la función (b) proporcionando 2 y pasa la llamada a la suma de múltiples argumentos original.



------------------------------------

Aquí hay un ejemplo de juguete en Python:

>>> from functools import partial as curry

>>> # Original function taking three parameters:
>>> def display_quote(who, subject, quote):
        print who, 'said regarding', subject + ':'
        print '"' + quote + '"'


>>> display_quote("hoohoo", "functional languages",
           "I like Erlang, not sure yet about Haskell.")
hoohoo said regarding functional languages:
"I like Erlang, not sure yet about Haskell."

>>> # Let's curry the function to get another that always quotes Alex...
>>> am_quote = curry(display_quote, "Alex Martelli")

>>> am_quote("currying", "As usual, wikipedia has a nice summary...")
Alex Martelli said regarding currying:
"As usual, wikipedia has a nice summary..."

(Solo uso la concatenación a través de + para evitar distracciones para los programadores que no usan Python).

Edición para agregar:

Consulte http://docs.python.org/library/functools.html?highlight=partial#functools.partial, que también muestra la distinción parcial entre objeto y función en la forma en que Python implementa esto.

Respondido al

30 de agosto de 2009 a las 17:47

Anónimo

Anónimo

11,9k

3

3 insignias de oro

23

23 insignias de plata

19

19 bronce insignias

8

No entiendo esto, haz esto: >>> am_quote = curry(display_quote, "Alex Martelli") pero luego haces lo siguiente: >>> am_quote("currying", "Como siempre,wikipedia tiene un buen resumen...") Entonces tienes una función con dos argumentos. ¿Parecería que el curry debería darte tres funciones diferentes que componerías?

usuario140327

30/08/2009 a las 21:46

1

Estoy usando parcial para curry solo un parámetro, produciendo una función con dos argumentos. Si lo desea, puede recurrir a am_quote para crear uno que solo cite a Alex sobre un tema en particular. El trasfondo matemático puede centrarse en terminar con funciones con un solo parámetro, pero creo que arreglar cualquier número de parámetros lAsí, esto se llama comúnmente (aunque de manera imprecisa desde un punto de vista matemático) curry.

- Anónimo

31 de agosto de 2009 a las 1:43

(por cierto, '>>>' es el mensaje en el intérprete interactivo de Python, no parte del código).

- Anónimo

31 de agosto de 2009 a las 2:20

Bien, gracias por la aclaración sobre args. Conozco el mensaje del intérprete de Python, estaba trIntento citar las líneas pero no funcionó ;-)

usuario140327

31 de agosto de 2009 a las 3:49

Después de tu comentario, busqué y encontré otras referencias, incluso aquí en SO, a la diferencia entre "curry" y. "aplicación parcial" en respuesta a muchos casos de uso impreciso con los que estoy familiarizado. Consulte, por ejemplo: stackoverflow.com/questions/218025/…

- Anónimo

31 de agosto de 2009 a las 4:47



------------------------------------

Aquí está el ejemplo de la versión genérica y más corta para la función curry con n no. de parámetros.

const add = a => b => b ? add(a + b) : a; 

const add = a => b => b ? add(a + b) : a; 
console.log(add(1)(2)(3)(4)());



------------------------------------

El curry es una de las funciones de orden superior de Java Script.

Currying es una función de muchos argumentos que se reescribe de manera que toma el primer argumento y devuelve una función que a su vez utiliza los argumentos restantes y devuelve el valor.

¿Confundido?

Veamos un ejemplo,

function add(a,b)
    {
        return a+b;
    }
add(5,6);

Esto es similar a la siguiente función de curry,

function add(a)
    {
        return function(b){
            return a+b;
        }
    }
var curryAdd = add(5);
curryAdd(6);

Así que¿Qué significa este código?

Ahora lee la definición de nuevo,

Currying es una función de muchos argumentos que se reescribe de manera que toma el primer argumento y devuelve una función que a su vez utiliza los argumentos restantes y devuelve el valor.

Aún así, ¿confundido? ¡Déjame explicarte en profundidad!

Cuando llamas a esta función,

var curryAdd = add(5);

Te devolverá una función como esta,

curryAdd=function(y){return 5+y;}

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 de función de orden superior. Ésta es la mayor ventaja de la leyenda, Java Script. Así que volvamos al curry,

Esta línea pasará el segundo argumento a la función curryAdd.

curryAdd(6);

lo que a su vez resulta,

curryAdd=function(6){return 5+6;}
// Which results in 11

Hola¿Entiendes el uso del curry aquí? Entonces, llegando a las ventajas,

¿Por qué hacer curry?

Hace uso de la reutilización del código. Menos código, menos errores. Quizás te preguntes ¿cómo es que hay menos código?

Puedo probarlo con las nuevas funciones de flecha del script ECMA 6.

¡Sí! ECMA 6, nos proporciona la maravillosa característica llamada funciones de flecha,

function add(a)
    {
        return function(b){
            return a+b;
        }
    }

Con la ayuda de la función de flecha, podemos escribir la función anterior de la siguiente manera,

x=>y=>x+y

Genial, ¿verdad?

¡¡Entonces, menos código y menos errores!!

Con la ayuda de estas funciones de orden superior, uno puede desarrollar fácilmente un código libre de errores.

¡Te desafío!

Espero que hayas entendido lo que es el curry. No dude en comentar aquí si necesita alguna aclaración.

¡Gracias, que tengas un buen día!

Respondido al

3 de junio de 2020 a las 6:27

sabitha kuppusamy

sabitha kuppusamy

96

1

1 insignia de plata

4

4 insignias de bronce



------------------------------------

Si entiendes parcial, estás a medio camino. La idea de parcial es aplicar previamente 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 concualesquiera argumentos que se le hayan proporcionado.

En Clojure + es una función, pero para dejar las cosas muy claras:

(defn add [a b] (+ a b))

Es posible que sepa que la función inc simplemente suma 1 al número que se pasa.

(inc 7) # => 8

Vamos a construirlo nosotros mismos usando parcial:

(def inc (partial add 1))

Aquí devolvemos otra función que tiene 1 cargado en el primer argumento de add. Como add toma dos argumentos, la nueva función inc solo quiere el argumento b, no 2 argumentos como antes, ya que 1 ya se aplicó parcialmente. Por lo tanto, parcial es una herramienta desde la cual crear nuevas funciones con valores predeterminados previamente suministrados. Es por eso que en un lenguaje funcional las funciones suelen ordenar los argumentos de lo general a lo específico. Esto hace que sea más fácil reutilizar dichas funciones para construir otras funciones.

NAhora imaginemos si el lenguaje fuera lo suficientemente inteligente como para entender introspectivamente que Add quería dos argumentos. Cuando le pasamos un argumento, en lugar de resistirnos, ¿qué pasaría si la función aplicara parcialmente el argumento? Le pasamos en nuestro nombre, entendiendo que probablemente teníamos la intención de proporcionar el otro argumento más adelante. Entonces podríamos definir inc sin usar explícitamente parcial.

(def inc (add 1)) #partial is implied

Así es como 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.



------------------------------------

El curry puede simplificartu codigo. Esta es una de las principales razones para utilizarlo. Currying 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, almacenarlos en otra función y tratarlos como un valor de retorno, y estas funciones forman una cadena, y se pasan los argumentos finales. para completar la operación.

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 legibilidad del programa. Esto también hace que el programa sea más manejable. Además, dividir el código en partes más pequeñas facilitaría su reutilización.

Por ejemplo:

function curryMinus(x) 
{
  return function(y) 
  {
    return x - y;
  }
}

var minus5 = curryMinus(1);
minus5(3);
minus5(5);

Yo también puedo hacer...

var minus7 = curryMinus(7);
minus7(3);
minus7(5);

Esto es muy bueno para hacer que el código complejo sea ordenado y para manejar métodos no sincronizados, etc.



------------------------------------

Este artículo, y el artículo al que hace referencia, me parecieron útiles para comprender mejor el curry: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx

Como mencionaron los demás, es solo una forma de tener una función de un solo 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.



------------------------------------

Como todas las demás respuestas, el curry ayuda a crear funciones parcialmente aplicadas. Javascript no proporciona soporte nativo para el curry automático. Por lo tanto, es posible que los ejemplos proporcionados anteriormente no ayuden en la codificación práctica. Hay un ejemplo excelente en livescript (que esencialmente se compila en js) http://livescript.net/

times = (x, y) --> x * y
times 2, 3       #=> 6 (normal use works as expected)
double = times 2
double 5         #=> 10

En el ejemplo anterior, cuando has dado menos argumentos, Livescript genera una nueva función de curry para ti (doble)



------------------------------------

La mayoría de los ejemplos en este hilo son artificiales (sumando números). Estos son útiles para ilustrar el concepto, pero no motivan cuándo podrías usar curry en una aplicación.

Aquí hay un ejemplo práctico de React, la biblioteca de interfaz de usuario de JavaScript. El curry aquí ilustra la propiedad de cierre.

Como es típico en la mayoría de las bibliotecas de interfaz de usuario, cuando el usuario hace clic en un botón, se llama a una función para manejar el evento. El controlador normalmente modifica el estado de la aplicación y activa la interfaz para que se vuelva a representar.

Las listas de elementos son componentes comunes de la interfaz de usuario. Cada elemento puede tener un identificador asociado (normalmente relacionado con un registro de la base de datos). Cuando el usuario hace clic en un botón para,por ejemplo, "me gusta" un elemento de la lista, el controlador necesita saber en qué botón se hizo clic.

El curry es un enfoque para lograr la unión entre id y handler. En el código siguiente, makeClickHandler es una función que acepta una identificación y devuelve una función de controlador que tiene la identificación en su alcance.

El funcionamiento de la función interna no es importante para esta discusión. Pero si tiene curiosidad, busca en el conjunto de elementos para encontrar un elemento por identificación e incrementa sus "me gusta", lo que activa otro renderizado al establecer el estado. El estado es inmutable en React, por lo que se necesita un poco más de trabajo para modificar un valor de lo que cabría esperar.

Puedes pensar en invocar la función curry como "eliminar" la función. desactivar la función externa para exponer una función interna listaser llamado. Esa nueva función interna es el controlador real pasado a onClick de React. La función externa es un cierre para que el cuerpo del bucle especifique la identificación que estará dentro del alcance de una función de controlador interno particular.

const List = () => {
  const [items, setItems] = React.useState([
    {name: "foo", likes: 0},
    {name: "bar", likes: 0},
    {name: "baz", likes: 0},
  ].map(e => ({...e, id: crypto.randomUUID()})));

  //    .----------.   outer func  inner func
  //    | currying |         |       |
  //    `----------`         V       V
  const makeClickHandler = (id) => (event) => {
    setItems(prev => {
      const i = prev.findIndex(e => e.id === id);
      const cpy = {...prev[i]};
      cpy.likes++;
      return [
        ...prev.slice(0, i),
        cpy,
        ...prev.slice(i + 1)
      ];
    });
  };

  return (
    <ul>
    {items.map(({name, likes, id}) =>
      <li key={id}>
        <button
          onClick={
            /* strip off first function layer to get a click
               handler  bound to `id` and pass it to onClick */
            makeClickHandler(id)
          }
        >
          {name} ({likes} likes)
        </button>
      </li>
    )}
    </ul>
  );
};

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<List />);
button {
  font-family: monospace;
  font-size: 2em;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>



------------------------------------

Se aplica una función curry a múltiples listas de argumentos, en lugar de solo uno.

Aquí hay una función normal, sin curry, que agrega dos Int parámetros, x e y:

scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int,y: Int)Int
scala> plainOldSum(1, 2)
res4: Int = 3

Aquí hay una función similar al curry. En cambio de una lista de dos parámetros Int, aplica esta función a dos listas de un Intpparámetro cada uno:

scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)Intscala> second(2)
res6: Int = 3
scala> curriedSum(1)(2)
res5: Int = 3

Lo que sucede aquí es que cuando invocas currySum, en realidad obtienes dos invocaciones de funciones tradicionales consecutivas. La primera función la invocación toma un único parámetro Int llamado x y devuelve una función valor para la segunda función. Esta segunda función toma el parámetro Int. y.

Aquí hay una función nombrada primero que hace en espíritu lo que la primera función tradicional La invocación de la función CurrySum haría:

scala> def first(x: Int) = (y: Int) => x + y
first: (x: Int)(Int) => Int

Aplicar 1 a la primera función; en otras palabras, invocar la primera función y pasando 1 —produce la segunda función:

scala> val second = first(1)
second: (Int) => Int = <function1>

Aplicar 2 a la segunda función produce el resultado:

scala> second(2)
res6: Int = 3



------------------------------------

Un ejemplo de curry sería cuando tienes funciones y solo conoces uno de los parámetros en este momento:

Por ejemplo:

func aFunction(str: String) {
    let callback = callback(str) // signature now is `NSData -> ()`
    performAsyncRequest(callback)
}

func callback(str: String, data: NSData) {
    // Callback code
}

func performAsyncRequest(callback: NSData -> ()) {
    // Async code that will call callback with NSData as parameter
}

Aquí, dado que no conoce el segundo parámetro para la devolución de llamada cuando lo envía a performAsyncRequest(_:), tendría que crear otro lambda/cierre para enviarlo a la función.

2

¿La devolución de llamada de func regresa sola? Se llama @ callback(str), así que deja que se devuelva la llamada.= devolución de llamada (cadena), la devolución de llamada es solo el valor de retorno de la devolución de llamada de func

-nikk wong

4 de septiembre de 2016 a las 0:22

no, func callback(_:data:) acepta dos parámetros, aquí solo le doy uno, el String, por lo que está esperando el siguiente (NSData), es por eso que ahora let callback es otra función esperando datos a pasar

- S2dent

5 septiembre 2016 a las 21:49



------------------------------------

Aquí puedes encontrar una explicación sencilla.ción de la implementación de curry en C#. En los comentarios, he intentado mostrar lo útil que puede ser el curry:

public static class FuncExtensions {
    public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
    {
        return x1 => x2 => func(x1, x2);
    }
}

//Usage
var add = new Func<int, int, int>((x, y) => x + y).Curry();
var func = add(1);

//Obtaining the next parameter here, calling later the func with next parameter.
//Or you can prepare some base calculations at the previous step and then
//use the result of those calculations when calling the func multiple times 
//with different input parameters.

int result = func(1);



------------------------------------

"Currying" es el proceso de tomar la función de múltiples argumentos y convertirla en una serie de funciones, cada una de las cuales toma un solo argumento y devuelve una función de un solo argumento, o en el caso de la función final, devuelve el resultado real.

Respondido

28 de noviembre de 2020 a las 10:54

Abhishek Choudhary

Abhishek Choudhary

373

6

6 insignias de plata

16

16 insignias de bronce



------------------------------------

Las otras respuestas han dicho qué es el curry: pasar menos argumentos a una función con curry de los que espera no es un error, sino que devuelve una función que espera el resto de los argumentos y devuelve el mismo resultado que si los hubiera pasado. todo dentro a la vez.

Intentaré explicar por qué es útil. Es una de esas herramientas que nunca te diste cuenta de que necesitabas hasta que lo hiciste. El curry es sobre todo una manera de hacer tus programas.más expresivo: puedes combinar operaciones con menos código.

Por ejemplo, si tiene una función de curry add, puede escribir el equivalente de JS x => k + x (o Python lambda x: k + x o Ruby { |x| k + x } o Lisp (lambda (x) (+ k x)) o…) como simplemente agregar (k). En Haskelll puedes incluso usar el operador: (k +) o (+ k) (Las dos formas te permiten buscar operadores no conmutativos de cualquier manera: (/ 9) es una función que divide un número por 9, lo que probablemente sea (es el caso de uso más común, pero también tiene (9 /) para una función que divide 9 entre su argumento). Además de ser más corta, la versión curry no contiene ningún nombre de parámetro inventado como la x que se encuentra en todas las demás versiones. No es necesario. Estás definiendo una función que suma una constante k a un número y no necesitas gDale un nombre a ese número solo para hablar de la función. O incluso definirlo. Este es un ejemplo de lo que se llama "estilo sin puntos". Puede combinar operaciones teniendo en cuenta nada más que las operaciones mismas. No es necesario declarar funciones anónimas que no hagan más que aplicar alguna operación a su argumento, porque eso es lo que ya son las operaciones.

Esto resulta muy útil con funciones de orden superior cuando se definen de forma sencilla. Por ejemplo, un mapa al curry (fn, lista) le permite definir un asignador con solo map(fn) que se puede aplicar a cualquier lista más adelante. Pero curry un mapa definido en su lugar como map(list, fn) solo le permite definir una función que aplicará alguna otra función a una lista constante, lo que probablemente sea menos útil en general.

Currying reReduce la necesidad de cosas como tuberías y roscas. En Clojure, puedes definir una función de conversión de temperatura usando la macro de subprocesamiento ->: (defn f2c (deg) (-> deg (- 32) (* 5) (/ 9)). Eso es genial, se lee muy bien a la izquierda. a la derecha (“resta 32, multiplica por 5 y divide por 9”) y solo tienes que mencionar el parámetro dos veces en lugar de una vez para cada suboperación… pero solo funciona porque -> es una macro que transforma sintácticamente toda la forma antes de que se evalúe algo. Se convierte en una expresión anidada regular detrás de escena: (/ (* (- deg 32) 5) 9). Si las operaciones matemáticas fueran curiosas, no necesitarías una macro para combinarlas tan bien, como en Haskell, sea f2c = (resta 32) & (* 5) & (/ 9). (Aunque, ciertamente, sería más idiomático usar la función composition, que se lee de derecha a izquierda: (/ 9). (*5) . (resta 32).)

Nuevamente, es difícil encontrar buenos ejemplos de demostración; El curry es más útil en casos complejos donde realmente ayuda a la legibilidad de la solución, pero requieren tantas explicaciones solo para que comprendas el problema que la lección general sobre el curry puede perderse en el ruido.

2

1

Diste muchos ejemplos de cómo, pero ni un solo buen argumento de por qué. Me gustaría explicar ese punto, ya que creo que es a lo que te refieres.¿Qué te gustaría hacer al comienzo de tu publicación?

Geometría Sagrada

25/11/2021 a las 16:29

Es sólo una característica del idioma sin la que puedes vivir. No necesariamente útil. A algunas personas simplemente les gusta agregar nuevas características al lenguaje, lo que hace que sea más difícil de entender y lograr el mismo resultado de una manera diferente. si necesita n argumentos para completar, necesita n argumentos. La única ventaja puede ser reutilizar una función con menos argumentos si se puede reutilizar para otro propósito. Lo haríamos de todos modos.

- Melón de invierno

12 de abril de 2023 a las 20:24



------------------------------------

Este es el famoso cierre:

function add() {
  let a = 0;
  return function(b) {   
    return a + b;
  };
}

Y este es el curry mágico

function add(a) {
  return function(b) {
    return a + b;
  };
}



------------------------------------

Hay un ejemplo de "Currying en ReasonML".

let run = () => {
    Js.log("Curryed function: ");
    let sum = (x, y) => x + y;
    Printf.printf("sum(2, 3) : %d\n", sum(2, 3));
    let per2 = sum(2);
    Printf.printf("per2(3) : %d\n", per2(3));
  };



------------------------------------

A continuación se muestra un ejemplo de curry en JavaScript, aquí multiplicar devuelve la función que se utiliza para multiplicar x por dos.

const multiply = (presetConstant) => {
  return (x) => {
    return presetConstant * x;
  };
};

const multiplyByTwo = multiply(2);

// now multiplyByTwo is like below function & due to closure property in JavaScript it will always be able to access 'presetConstant' value
// const multiplyByTwo = (x) => {
//   return presetConstant * x;
// };

console.log(`multiplyByTwo(8) : ${multiplyByTwo(8)}`);

Salida

multiplicar por dos(8) : 16



------------------------------------

Una forma más inteligente de curry sería usar Function.prototype.bind, es decir, invocar bind() en una función). De esa manera, no es necesario modificar la función como han demostrado otros.

function h(a, b) {
  return a*a + b*b;
}

var a = f.bind(this, 3);

a(4) == 5*5  // true

randomThread
c - La función de lista enlazada no me deja acceder a los índices después de su usoCómo devolver el puntero a una matriz de estructura en CError de sintaxis: no se puede acceder a un método privado en la biblioteca Dartjava: matriz con entradas aleatorias pero sin duplicados y mostrando el primer númeroreaccionarjs: ¿Cómo uso constantes dentro de las definiciones de tipo mecanografiado?dplyr: distribuye múltiples valores a valores únicos en el marco de datos en R¿Cómo puedo encontrar la complejidad temporal de un algoritmo?¿Cómo imprimir la suma de 2 números en MIPS?javascript - ¿Cómo llamar a un php con parámetro de un