La magia del Currying

domingo, 25 de abril de 2021

Introdúcete al mundo de la programación declarativa con currying, aprende ¿Qué es? ¿Cómo sé hacer? Y ¿Cómo usarlo?

El currying (currificación) es una técnica de computación que consiste en transformar funciones de múltiple aridad (argumentos) en una secuencia de funciones de aridad unaria, esto significa que, si tenemos una función multiply que recibe a y b y retorna la multiplicación de a y b, se transformará una función que recibiera a, retornara otra función que reciba b y luego esa función retorne su múltiplo.

JS
      
      const multiply = (a, b) => {
  return a * b
}

multiply(10, 10) // 100

const multiplyCurried = (a) => {
  return (b) => {
    return a * b
  }
}

multiplyCurried(10)(10) // 100
    

Esta forma te permite realizar llevar una función general a una función más específica, aunque el ejemplo no es práctico y no es necesario hacer currying para sí sola, entonces que ta si hacemos un ejemplo sencillo pero más práctico.

JS
      
      const mapCurried = (callback) => {
    return (array) => {
        return array.map(callback)
    }
}

const prop = (x) => {
    return (data) => {
        return data[x]
    }
}

const pluck = (p) => {
    return (data) => {
        return mapCurried(x => prop(p)(x))(data)
    }
}
...

const getWebsites = data => pluck("website")(data)

const usersWebsites = getWebsites(users)
    

En este ejemplo usamos currying para poder obtener propiedades, específicamente website de una lista de usuarios, aunque no vemos beneficios de escritura ni lectura en nuestro código pues hasta puede hacerse más difícil de leer que si lo hiciéramos si currying, para ello vamos a usar point free (un estilo de programación) que te permite simplificar el código y luego de que te logras acostumbrar a este estilo se hará más declarativo y fácil de leer.

Si pasas por argumento una funcion que recive directamente la misma cantidad de paramentros

JS
      
      ...

const pluck = (p) => {
    return (data) => {
        return mapCurried(x => prop(p)(x))(data)
    }
}

// pluck recibe p que es la propiedad de la data que se traera de la data que  esto se puede simplficar por que data ya esta siendo recibida por map
const pluck = (p) => {
        return mapCurried(x => prop(p)(x))
}

// Luego lo que podemos haces es que simplficar el callback de que se la pasa a mapCurried, porque x es el mismo parametro que recibe la funcion retornada
const pluck = (p) => {
        return mapCurried(prop(p))
}
...
    

El operador => te permite retornar implicitamente

JS
      
      const pluck = (p) => mapCurried(prop(p))
    

Con estas “reglas” sencillas podemos simplificar el código

JS
      
      const mapCurried = (callback) => (array) => array.map(callback)

const prop = (x) => (data) => data[x]

const pluck = (p) => mapCurried(prop(p))

...
const getWebsites = pluck("website")

const usersWebsites = getWebsites(users)
...
    

ahora vemos que el código se ha simplificado en cuanto su escritura, pero tenemos el principal problema y es la lectura, esta forma de crear código es una forma declarativa que te permite ver fácilmente que está haciendo el código, solo que para la comprensión del código es más compleja por lo cual lo que se puede hacer es practicar la point free y currying. Y por último miraremos una utilidad para hacer currying facilmente.

JS
      
      const curry = (fn) => (x) => (y) => fn(x, y)

const modulo = curry((a, b) => a % b)

modulo(2)(10) // 2
    

Esto aunque es confuso, mirémoslo paso a paso.

Primero, se declara la funcion que queremos operar valores futuros Segundo, se declara x con un valor Tercero, se declara y con un valor y se opera la fn con los valores de x y y

JS
      
      const curry = (fn) => (x) => (y) => fn(x, y)

// fn: (a, b) => a % b)
const modulo = curry((a, b) => a % b)

// x: 2
const moduleBy2 = modulo(2)

// y: 10
moduleBy2(10) // 2
    

Listo has aprendido las bases de currying y espero que lo uses poco a poco en tus proyectos

Lee más artículos