¿Qué es el 'curry'?

Resuelto Ben asked hace 16 años • 25 respuestas

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!)

Ben avatar Aug 31 '08 03:08 Ben
Aceptado

Currying es cuando se divide una función que toma múltiples argumentos en una serie de funciones cada una de las cuales toma 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 curry esta función:

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

Esta es una función que toma un argumento, ay devuelve una función que toma otro argumento, by 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, al igual que la add(3, 4)declaración.
  • La segunda declaración define una nueva función llamada add3que agregará 3 a su argumento. (Esto es lo que algunos podrían llamar un cierre).
  • La tercera declaración usa la add3operación para sumar 3 más 4, produciendo nuevamente 7 como resultado.
Kyle Cronin avatar Aug 30 '2008 20:08 Kyle Cronin

En un álgebra de funciones, tratar con funciones que toman múltiples argumentos (o su equivalente, un argumento que es una N-tupla) es algo poco elegante, pero, como demostraron Moses Schönfinkel (y, de forma independiente, Haskell Curry), no es necesario: todo need son funciones que toman un argumento.

Entonces, ¿cómo lidias con algo que naturalmente expresarías como, por ejemplo 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, sólo tienes 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 incluidos algunos relacionados con sus idiomas favoritos;-), así como un tratamiento matemático un poco más riguroso.

Alex Martelli avatar Aug 30 '2009 02:08 Alex Martelli

He aquí 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 los tres parámetros necesarios como argumentos.

Ahora, al estar en la Tierra, sólo 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.

Shea Daniels avatar Aug 30 '2009 02:08 Shea Daniels

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, se 10pasa 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 };

Entonces cuando llamas

 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

Entonces nuestro addTen()siempre suma diez a todo lo que 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 + yen una que se puede realizar con pereza, lo que significa que podemos hacer al menos dos cosas: 1. almacenar en caché operaciones costosas y 2. lograr abstracciones en el paradigma funcional.

Imagine 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 manera similar.

Adzz avatar Jan 14 '2016 17:01 Adzz