Aplicación parcial y currying

August 07, 2019

...

Hoy hablaremos sobre una técnica maravillosa que nos ayudará a redactar código más funcional y que, en episodios siguientes, nos ayudará a escribir un código más limpio, estamos hablando de currying y aplicación parcial (partial application).

Aplicación parcial de funciones

Supongamos el siguiente ejemplo:

const suma = (a, b) => a + b

La función de suma necesita dos argumentos, a y b, pero que ocurre si solo conocemos un solo argumento y no podemos o no queremos cambiar la implementación de la función suma?, en este caso podríamos intentar crear una función que tome solo el primer argumento y luego tome el segundo, y cuando haya tomado todos los argumentos ahí recién ejecutar la función de suma. Veamos como podemos escribirla:

const suma = (a, b) => a + b

const partial = a => b => suma(a, b)

Hemos creado una función llamada partial (la implementación es bastante ingenua, solo enfoquémonos en la explicación). Esta función partial toma el primer argumento pero no ejecuta la función suma. Esta se quedará esperando hasta que le pasemos el siguiente argumento (en total dos) para ahí recién ejecutar la función de suma. Cuando no tenemos todos los argumentos, pero sin embargo se lo pasamos a nuestra función y está aún no se ejecuta decimos que la función ha sido aplicada parcialmente. Llevémoslo a dos puntos:

  • no pasamos todos los argumentos a una función.
  • Esta no se ejecuta y queda esperando los argumentos restantes.

Aplicación parcial o partial application. En JavaScript se puede utilizar el método bind para hacer aplicación parcial de una función:

const suma = (a, b) => a + b
const suma1 = suma.bind(null, 1)
suma1(5) // 6

Aunque bind necesita que le pasemos también el contexto de this, nosotros le entregamos null ya que no estamos utilizando this. Pero si se debe tomar en cuenta de que el método de bind está pensado también para pasar un contexto, pero funciona muy bien para aplicaciones parciales.

Currying

El currying es una técnica utilizada para transformar todas las funciones en funciones unary. Las funciones unary tienes la particularidad de ser funciones que reciben solo un argumento, entonces, si la función debe recibir más de un argumento, como lo hacemos?, en ese caso retornamos una función que recibe otro argumento, y así sucesivamente hasta que recibe todos los argumentos que esta necesita para funcionar. Vamos a ver un ejemplo:

const suma = a => b => a + b
suma(1)(5) // 6

Lo mismo, no nos fijemos mucho en la implementación, todo esto hará más sentido cuando veamos composición de funciones.

En este caso la función suma recibe un argumento y esta retorna otra función que recibe otro argumento, esta es otra forma de realizar aplicación parcial a una función, donde esta no será ejecutada hasta que no apliquemos todos los argumentos necesarios.

Autocurrying

A veces nos vemos en la situación donde conocemos más de un solo argumento de una función, por lo que podríamos aplicar más de un argumento en determinada situación a una función, pero si nosotros realizamos curling de manera manual a nuestra función tendremos que llamarla cada vez que le pasemos un argumento:

const suma = a => b => c => d => e => a + b + c + d + e

suma(1)(5)(7)(3)(5)

Esto puede ser considerado engorroso o feo por algunos desarrolladores, así que veamos una forma que nos permita solucionar eso, podemos utilizar la función curry de lodash o de ramda. En lo personal prefiero ramda pero ya llegaremos a una explicación más detallada de ella más adelante, solo recuerda que el método es el mismo para lodash:

import { curry } from 'ramda'

const suma = curry((a, b, c, d, e) => a + b + c + d + e)

// todos estos llamados entregan el mismo resultado

suma(1, 2, 3, 4, 5)
suma(1)(2, 3, 4, 5)
suma(1, 2)(3, 4, 5)
suma(1)(2)(3, 4, 5)
suma(1)(2)(3)(4)(5)
suma(1, 2, 3)(4)(5)

Podría poner todas las combinaciones posibles pero creo que se entiende el punto.

Una función tiene autocurrying cuando esta es capas de discernir si todos los argumentos han sido aplicados, si no han sido todos aplicados (partial application) entonces esta retornará otra función que recibirá los argumentos faltantes.

Ahora la pregunta del millón:

Porque esto es útil?

Si nos quedamos solo con este post la utilidad es nula! bueno... tal vez no nula, pero todo quedará muchísimo más claro en nuestro siguiente post cuando veamos composición. Así que estén atentos al siguiente artículo!

Espero que les haya gustado este post, no olviden seguirme en twitter y youtube! Links más abajo.


Suscríbete

Suscríbete a la lista para más cursos, posts y videos tutoriales. Prometo no enviarte más de un correo semanal 🙏

Creado por Nicolás Schürmann ingeniero e instructor de software. Cuando no está programando, esta frente a una cámara dictando cursos, creyéndose youtuber o apoyando a sus alumnos. Puedes seguirlo en twitter o también suscribirte a su canal de youtube. Considera comprar sus cursos por este medio y así apoyas al instructor.