Saltar al contenido

Currificación y aplicación parcial en JavaScript

Currying y la aplicación parcial son técnicas potentes de programación funcional que pueden mejorar significativamente la modularidad y la reutilización de tu código JavaScript. En este artículo, profundizaremos en estos conceptos, exploraremos sus mejores prácticas y proporcionaremos ejemplos prácticos para ayudarte a dominar su uso.

Entender el currying

El currying es una técnica en la que una función se transforma en una secuencia de funciones, cada una de las cuales toma un solo argumento. Permite descomponer una función que toma múltiples argumentos en una serie de funciones unarias (de un solo argumento).

Ejemplo de currying

Considera una función simple que suma tres números:


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

Podemos transformar esta función en una versión currificada:


Output appears here after Run.

Explicación:

  • La función add toma tres argumentos y devuelve su suma.
  • La función curryAdd es una versión currificada de add. Toma un argumento a y devuelve otra función que toma b. Esta segunda función devuelve otra función que toma c. La función más interna devuelve la suma de a, b y c.

Beneficios del currying

  1. Reutilización: Las funciones currificadas te permiten crear nuevas funciones fijando algunos argumentos. Esto mejora la reutilización al permitirte crear fácilmente versiones especializadas de una función sin duplicar código.

Output appears here after Run.

Aquí, curriedAdd es una versión currificada de la función add. Nos permite crear funciones especializadas como add5 fijando el primer argumento (a) en 5. Esto promueve la reutilización del código, ya que podemos crear múltiples funciones especializadas sin repetir la lógica de la suma.

  1. Composición de funciones: El currying facilita la composición de funciones. La composición de funciones es el proceso de combinar dos o más funciones para producir una nueva función.

Output appears here after Run.

En este ejemplo, componemos las funciones multiply y addOne usando currying. Al currificar estas funciones, podemos crear fácilmente una nueva función addOneThenMultiplyBy5, que primero suma 1 a la entrada (x) y luego multiplica el resultado por 5. Esto demuestra cómo el currying facilita la composición de funciones, haciendo más sencillo crear nuevas funciones combinando las existentes.

Implementar currying en JavaScript

Podemos crear una función de utilidad para currificar cualquier función. Aquí tienes una implementación de una función genérica de currying:


Output appears here after Run.

Explicación:

  1. Función de currying (curry):

    • La función curry toma otra función fn como entrada.
    • Devuelve una nueva función llamada curried.
    • Esta función curried toma cualquier número de argumentos usando la sintaxis de parámetro rest (...args).
  2. Función currificada (curried):

    • Dentro de curried, comprueba si el número de argumentos proporcionados (args.length) es mayor o igual que el número de argumentos esperados por la función original fn (fn.length).
    • Si se proporcionan suficientes argumentos, llama a la función original fn con esos argumentos usando fn.apply(this, args).
    • Si no se proporcionan suficientes argumentos, devuelve una nueva función que acepta más argumentos (nextArgs) usando el operador spread (...nextArgs).
    • Esta nueva función recursivamente llama a curried con los argumentos combinados (args.concat(nextArgs)), asegurando que todos los argumentos se recopilen finalmente antes de llamar a la función original fn.

    Nota: fn.length solo cuenta los parámetros sin valores predeterminados e ignora los parámetros rest.

  3. Ejemplo de uso:

    • Definimos una función multiply que toma tres argumentos y devuelve su producto.
    • Creamos una versión currificada de la función multiply pasándola a la función curry, que devuelve una nueva función curriedMultiply.
    • Ahora, curriedMultiply puede llamarse con uno, dos o tres argumentos.
    • Cada vez que llamamos a curriedMultiply con uno o varios argumentos, devuelve una nueva función hasta que se recopilan todos los argumentos, momento en el que devuelve el resultado de multiplicar los argumentos entre sí.

Explorar la aplicación parcial

La aplicación parcial es una técnica en la que creas una nueva función rellenando previamente algunos argumentos de la función original. Esto es especialmente útil para crear funciones especializadas.

Ejemplo de aplicación parcial

Considera la siguiente función que formatea un mensaje:


javascript
function formatMessage(greeting, name) {
    return `${greeting}, ${name}!`;
}

Podemos crear una función aplicada parcialmente:


Output appears here after Run.

Explicación:

  • La función formatMessage toma dos argumentos, greeting y name, y devuelve un mensaje formateado.
  • La función partial toma una función fn y algunos argumentos preestablecidos (...presetArgs). Devuelve una nueva función que toma los argumentos restantes (...laterArgs).
  • Cuando se llama a la nueva función, combina presetArgs y laterArgs y llama a la función original fn con estos argumentos.
  • Usando partial, creamos greetHello, una función que siempre usa "Hello" como saludo. Cuando se llama con un nombre, devuelve el mensaje completo.

Beneficios de la aplicación parcial

  1. Simplificación: Crear funciones más simples a partir de otras más complejas

    Supongamos que tenemos una función que calcula el precio final de un artículo después de aplicar un descuento y un impuesto.


javascript
function calculateFinalPrice(price, discount, tax) {
    return price - (price * discount) + (price * tax);
}

Esta función requiere tres argumentos, lo que la hace un poco incómoda de usar repetidamente si las tasas de descuento e impuesto suelen ser las mismas. Con la aplicación parcial, podemos simplificar esto.


Output appears here after Run.

En el ejemplo anterior, applyDiscountAndTax es una función aplicada parcialmente que preestablece los valores de discount y tax. Esto facilita calcular el precio final de distintos artículos sin especificar repetidamente las tasas de descuento e impuesto.

  1. Reutilización del código: Reutilizar la lógica común de una función con diferentes argumentos preestablecidos

    Imagina que tenemos una función que registra mensajes con distintos niveles de severidad.


javascript
function logMessage(level, message) {
    console.log(`[${level}] ${message}`);
}

Podemos crear funciones reutilizables para distintos niveles de registro usando la aplicación parcial.


Output appears here after Run.

Aquí, createLogger es una función aplicada parcialmente que establece el argumento level. Las funciones infoLogger y errorLogger ahora pueden usarse para registrar mensajes con los niveles de registro preestablecidos, reutilizando la lógica común de logMessage.

  1. Mejor legibilidad: Hace que el código sea más legible al descomponer funciones complejas Considera una función que formatea fechas en distintos estilos.

javascript
function formatDate(date, format) {
    const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
    if (format === 'US') {
        options.month = 'long';
    } else if (format === 'EU') {
        options.day = 'numeric';
        options.month = 'numeric';
    }
    return new Date(date).toLocaleDateString(undefined, options);
}

Usando la aplicación parcial, podemos crear funciones más legibles para distintos formatos de fecha.


Output appears here after Run.

createDateFormatter aplica parcialmente el argumento format, dando como resultado funciones específicas para formatos de fecha de EE. UU. y de la UE. Esta descomposición hace que el código sea más legible y fácil de entender, ya que cada formateador está dedicado a un formato concreto.

Estos ejemplos ilustran cómo la aplicación parcial en JavaScript puede simplificar funciones complejas, mejorar la reutilización del código y mejorar la legibilidad, haciendo que el código sea más fácil de mantener y entender.

Mejores prácticas para usar currying y aplicación parcial

Mantén las funciones puras

  • Asegúrate de que las funciones currificadas y aplicadas parcialmente sigan siendo puras, sin efectos secundarios. Esto las hace más fáciles de razonar y de probar.

Úsalas cuando corresponda

  • Usa currying y aplicación parcial cuando encajen de forma natural con el problema que estás resolviendo.
  • Evita abusar de estas técnicas, ya que pueden hacer que el código sea más difícil de entender si no se usan con criterio.

Aprovecha la composición de funciones

  • Combina funciones currificadas para crear funcionalidades más complejas. El currying funciona bien con la composición de funciones, lo que da lugar a un código más modular.

Documentación y nombres

  • Documenta correctamente las funciones currificadas y aplicadas parcialmente para indicar su uso esperado.
  • Usa nombres claros y descriptivos para las funciones, de modo que transmitan su propósito.

INFO

Si usas con frecuencia currying y aplicación parcial, considera usar la biblioteca Lodash, que proporciona funciones de utilidad prácticas como _.curry y _.partial.

Combinar con métodos de arrays

El currying puede combinarse eficazmente con métodos de array como map, filter y reduce para obtener un código conciso y expresivo.


Output appears here after Run.

Explicación:

  • La función curriedMultiply se usa para crear multiplyByTwo, una función que multiplica su argumento por 2.
  • El array numbers se transforma usando map, aplicando multiplyByTwo a cada elemento, lo que da como resultado un nuevo array de números duplicados.

Conclusión

El currying y la aplicación parcial en JavaScript ofrecen técnicas potentes para simplificar la composición de funciones, mejorar la reutilización del código y mejorar la legibilidad. El currying transforma funciones con múltiples argumentos en una serie de funciones unarias, lo que permite un código más flexible y modular. La aplicación parcial permite preestablecer argumentos de función, facilitando la reutilización del código y la simplificación de funciones complejas. Al aprovechar estos conceptos de programación funcional, los desarrolladores pueden escribir código JavaScript más limpio, más conciso y más fácil de mantener.

Practice

What is correct about Currying in JavaScript?

¿Te resulta útil?

Vista previa dual-run — compárala con las rutas Symfony en producción.