Introducción a la programación funcional a nivel avanzado
\n\nLa programación funcional (PF) es un paradigma que considera los cálculos como la ejecución de funciones matemáticas y evita el cambio de estado y los datos mutables. En JavaScript, especialmente en el entorno Node.js, la PF se vuelve cada vez más popular debido a su previsibilidad, capacidad de prueba y paralelismo.
\n\nSi ya has dominado los fundamentos de la PF (funciones puras, funciones de orden superior, map, filter, reduce), es hora de pasar al siguiente nivel. En este artículo, analizaremos conceptos avanzados: currificación, composición, mónadas y trabajo con datos inmutables.
1. Currificación y aplicación parcial
\n\n¿Qué es la currificación?
\nLa currificación es el proceso de transformar una función que toma varios argumentos en una secuencia de funciones, cada una de las cuales toma un solo argumento. Esto permite crear funciones especializadas a partir de funciones generales.
\n\n// Función normal\nconst add = (a, b, c) => a + b + c;\nconsole.log(add(1, 2, 3)); // 6\n\n// Versión currificada\nconst curriedAdd = a => b => c => a + b + c;\nconsole.log(curriedAdd(1)(2)(3)); // 6\n\n// Función universal de currificación\nconst curry = (fn) => {\n const arity = fn.length;\n const resolver = (...args) => {\n if (args.length < arity) {\n return (...nextArgs) => resolver(...args, ...nextArgs);\n }\n return fn(...args);\n };\n return resolver;\n};\n\nconst multiply = (a, b, c) => a * b * c;\nconst curriedMultiply = curry(multiply);\nconsole.log(curriedMultiply(2)(3)(4)); // 24\nconsole.log(curriedMultiply(2, 3)(4)); // 24\n\nAplicación parcial
\nLa aplicación parcial es la fijación de una parte de los argumentos de una función, creando una nueva función con menos argumentos. A diferencia de la currificación, la aplicación parcial no requiere una secuencia estricta de llamadas.
\n\nconst partial = (fn, ...presetArgs) => (...laterArgs) => fn(...presetArgs, ...laterArgs);\n\nconst greet = (greeting, name) => `${greeting}, ${name}!`;\nconst sayHello = partial(greet, 'Hello');\nconst sayHi = partial(greet, 'Hi');\n\nconsole.log(sayHello('Alice')); // Hello, Alice!\nconsole.log(sayHi('Bob')); // Hi, Bob!\n\n2. Composición de funciones
\n\nComposición avanzada
\nLa composición es el proceso de combinar varias funciones para crear una nueva función. En la PF avanzada, usamos composición de derecha a izquierda (compose) y de izquierda a derecha (pipe).
// Composición simple (de derecha a izquierda)\nconst compose = (...fns) => (value) => fns.reduceRight((acc, fn) => fn(acc), value);\n\n// Composición de izquierda a derecha (pipe)\nconst pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value);\n\n// Ejemplo: procesamiento de cadenas\nconst trim = (str) => str.trim();\nconst toLowerCase = (str) => str.toLowerCase();\nconst capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);\nconst removeSpaces = (str) => str.replace(/\\s+/g, '-');\n\nconst slugify = compose(capitalize, toLowerCase, trim, removeSpaces);\n// Equivalente: removeSpaces(trim(toLowerCase(capitalize(" Hello World "))))\n\nconsole.log(slugify(' Hello World ')); // Hello-world\n\nTransductores (Transducers)
\nLos transductores son la composición de funciones de transformación que trabajan con cualquier estructura de datos iterable. Permiten combinar varias operaciones (por ejemplo, map y filter) en una sola pasada.
const transducer = (mapper, predicate) => (reducer) => (acc, value) => {\n const mapped = mapper(value);\n return predicate(mapped) ? reducer(acc, mapped) : acc;\n};\n\nconst double = (x) => x * 2;\nconst isEven = (x) => x % 2 === 0;\n\nconst processNumbers = transducer(double, isEven);\nconst sumReduc