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:
function add(a, b, c) {
return a + b + c;
}Podemos transformar esta función en una versión currificada:
Explicación:
- La función
addtoma tres argumentos y devuelve su suma. - La función
curryAddes una versión currificada deadd. Toma un argumentoay devuelve otra función que tomab. Esta segunda función devuelve otra función que tomac. La función más interna devuelve la suma dea,byc.
Beneficios del currying
- 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.
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.
- 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.
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:
Explicación:
Función de currying (
curry):- La función
currytoma otra funciónfncomo entrada. - Devuelve una nueva función llamada
curried. - Esta función
curriedtoma cualquier número de argumentos usando la sintaxis de parámetro rest (...args).
- La función
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 originalfn(fn.length). - Si se proporcionan suficientes argumentos, llama a la función original
fncon esos argumentos usandofn.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
curriedcon los argumentos combinados (args.concat(nextArgs)), asegurando que todos los argumentos se recopilen finalmente antes de llamar a la función originalfn.
Nota:
fn.lengthsolo cuenta los parámetros sin valores predeterminados e ignora los parámetros rest.- Dentro de
Ejemplo de uso:
- Definimos una función
multiplyque toma tres argumentos y devuelve su producto. - Creamos una versión currificada de la función
multiplypasándola a la funcióncurry, que devuelve una nueva funcióncurriedMultiply. - Ahora,
curriedMultiplypuede llamarse con uno, dos o tres argumentos. - Cada vez que llamamos a
curriedMultiplycon 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í.
- Definimos una función
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:
function formatMessage(greeting, name) {
return `${greeting}, ${name}!`;
}Podemos crear una función aplicada parcialmente:
Explicación:
- La función
formatMessagetoma dos argumentos,greetingyname, y devuelve un mensaje formateado. - La función
partialtoma una funciónfny algunos argumentos preestablecidos (...presetArgs). Devuelve una nueva función que toma los argumentos restantes (...laterArgs). - Cuando se llama a la nueva función, combina
presetArgsylaterArgsy llama a la función originalfncon estos argumentos. - Usando
partial, creamosgreetHello, 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
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.
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.
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.
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.
function logMessage(level, message) {
console.log(`[${level}] ${message}`);
}Podemos crear funciones reutilizables para distintos niveles de registro usando la aplicación parcial.
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.
- 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.
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.
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.
Explicación:
- La función
curriedMultiplyse usa para crearmultiplyByTwo, una función que multiplica su argumento por 2. - El array
numbersse transforma usandomap, aplicandomultiplyByTwoa 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?