Curry en JS

¡Hola Mundo!

JavaScript es un lenguaje de programación multiparadigma, lo que significa que admite tanto la programación procedimental como la funcional. La programación funcional te permite hacer cosas divertidas, casi mágicas. Un ejemplo de ello: el curry. En esta publicación, intentaremos comprender qué es el curry y cómo implementarlo de una manera sencilla.

Funciones de orden superior

Para implementar curry, necesitamos aprender sobre funciones de orden superior. Entonces, ¿qué es un HOF?

Cuando hablamos de funciones de orden superior, nos referimos a una función que toma una o más funciones como argumentos, o devuelve una función como resultado.

Solo encontrará funciones de orden superior en lenguajes de programación que admitan funciones de primera clase (o que traten las funciones como ciudadanos de primera clase). Esto significa un lenguaje que nos permite almacenar funciones en variables, pasarlas como parámetros en llamadas de función o devolverlas como resultado de otra llamada de función.

¡Uf! Eso suena complejo. Bueno, no lo es. Porque lo más probable es que ya esté usando HOF en su código. ¿Recuerda mapear, filtrar y reducir? Son funciones de orden superior.

Hagamos una función simple de orden superior.

const doubleFunc = fn => {
  return (...args) => {
    return 2 * fn(...args);
  };
};

Entonces, ¿qué está pasando aquí?

Escribimos una función llamada doubleFunc que toma una función fn como argumento y devuelve una nueva función que toma un número arbitrario de argumentos. Al proporcionar este número arbitrario de argumentos a esta función, se aplica fn a ellos, multiplica el resultado por 2 y devuelve el resultado.

Hemos recopilado el número arbitrario de argumentos en la matriz args anterior mediante el uso del operador spread/rest (…) en ES6. Lea más sobre esto en el increíble libro de Kyle Simpson. aquí.

const add = (x, y) => x + y;
const doubleAdd = doubleFunc(add);

console.log(doubleAdd(1, 4)); //=> 10

¿Enfriar? Enfriar.

Zurra

Ahora que entendemos qué es una función de orden superior, ¿cómo podemos aprovechar este conocimiento para hacer una utilidad de curry? Primero definamos curry.

Currying es el proceso de tomar una función con múltiples argumentos y devolver una serie de funciones que toman un argumento y finalmente se resuelven en un valor.

Bueno, eso es un poco difícil de entender. En términos simples, curry es el proceso de transformar una función que toma múltiples argumentos en una función que toma menos argumentos arreglando algunos de los argumentos.

Escribamos un par de funciones de incremento modificando add.

const add = x => y => x + y;
const inc1 = add(1);
const inc2 = add(2);

inc1(4); //=> 5
inc2(4); //=> 6

¡Excelente! Curriendo nuestro add hemos hecho que su lógica sea reutilizable y hemos extraído 2 funciones de ella.

Eso está bien y todo, pero ¿cómo podemos curry cualquier función? Escribamos una utilidad para esto.

function curry(fn) {
  return function(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    }

return function(...more) {
      return curry(fn)(...args, ...more);
    };
  };
}

Bien, vamos a desglosarlo. Escribimos una función llamada curry que toma una función fn como argumento y devuelve una función de n-aridad (una función que toma un número arbitrario de argumentos). Ahora, esta función hace un par de cosas.

  1. Si el número de argumentos proporcionados a esta función es igual o mayor que el número de argumentos que necesita la función fnsimplemente invoca fn con estos argumentos.
  2. De lo contrario, devuelve otra función de n-aridad que, cuando se proporciona alguna more argumentos, trata de invocar el curry fn con args y more.

Este proceso continúa hasta que se cumple la condición del paso 1.

Si no entiende lo que está sucediendo aquí, lo animo a copiar esta utilidad, agregarle registradores y usarla para crear una función propia.

El fragmento anterior es demasiado detallado. Reescribámoslo con funciones de flecha.

const curry = fn => (...args) =>
  args.length >= fn.length ? 
  fn(...args) :
  (...more) => curry(fn)(...args, ...more);

¡Mucho más fresco! Usemos este poder recién descubierto.

const sort = (ascend, list) => {
  const ascCmp = (a, b) => a > b;
  const dscCmp = (a, b) => a < b;
  return [...list].sort(ascend ? ascCmp : dscCmp);
};

const curriedSort = curry(sort);

const sortAsc = curriedSort(true);

const sortDsc = curriedSort(false);

const data = [9, 99, 29, 42, 45, 57, 13];

sortAsc(data); //=> [9, 13, 29, 42, 45, 57, 99]

sortDsc(data); //=> [99, 57, 45, 42, 29, 13, 9]

al curry sortfuimos capaces de aplicar parcialmente la función fijando el valor de ascend marca y almacena la función resultante, que ahora solo toma una lista de números, en una variable separada.

La aplicación parcial de funciones puede ayudarnos a reutilizar nuestras funciones de una manera más limpia. Incluso podemos pasar estas funciones aplicadas parcialmente en nuestra aplicación para una evaluación retrasada en la línea de ejecución cuando los argumentos restantes estén disponibles para nosotros.

Las funciones de orden superior son el pan y la mantequilla de la programación funcional, y las funciones de curry y parcialmente aplicadas permiten que las funciones de orden superior se utilicen de manera mucho más efectiva y concisa. Pero los HOF permiten mucho más que solo curry, cosas como composición, memorización y transducción, etc.

Si te gustó este sabor de la programación funcional en JS, deberías consultar estas bibliotecas de programación funcional: En el marco y lodash/fp.

Eso es todo para curry, chicos. Espero que hayas aprendido algo sobre esta genial técnica. Si te ha gustado este post, aplaude y comparte. ¡Ciao!

Similar Posts

Leave a Reply

Your email address will not be published.