DevHub Global Solutions | Educativo

Programación funcional: currying y composición

Descubre el poder de la programación funcional en JavaScript con técnicas avanzadas de currying y composición de funciones. Transforma tu enfoque de desarrollo con código más expresivo, reusable y mantenible.
Programación funcional: currying y composición
Diagrama de composición de funciones y currying

Currying: Funciones Especializadas

Transforma funciones multi-argumento en secuencias de funciones unarias:

// Función normal
const sumar = (a, b, c) => a + b + c;

// Versión currificada
const sumarCurry = a => b => c => a + b + c;

// Uso
sumarCurry(2)(3)(5); // 10

// Aplicación parcial
const sumar2 = sumarCurry(2);
const sumar5 = sumar2(3);
sumar5(5); // 10

// Currying automático
const curry = (fn) => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return (...args2) => curried.apply(this, args.concat(args2));
    }
  };
};

const multiplicar = (a, b, c) => a * b * c;
const multiplicarCurry = curry(multiplicar);

console.log(multiplicarCurry(2)(3)(4)); // 24

Composición de Funciones

Combina funciones simples para crear comportamientos complejos:

// Composición básica
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

// Ejemplo
const doble = x => x * 2;
const incrementar = x => x + 1;
const cuadrado = x => x ** 2;

// compose: f(g(x))
const transformar = compose(cuadrado, incrementar, doble);
transformar(3); // ((3*2)+1)**2 = 49

// pipe: g(f(x))
const transformarPipe = pipe(doble, incrementar, cuadrado);
transformarPipe(3); // ((3*2)+1)**2 = 49

pipe ejecuta de izquierda a derecha, compose de derecha a izquierda

Aplicaciones Prácticas

Implementaciones en código real:

// Validación de formularios
const validarLongitud = min => valor => 
  valor.length >= min;

const validarEmail = valor => 
  /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(valor);

const crearValidador = (...validadores) => valor =>
  validadores.every(validador => validador(valor));

const validarPassword = crearValidador(
  validarLongitud(8),
  valor => /[A-Z]/.test(valor),
  valor => /[0-9]/.test(valor)
);

console.log(validarPassword('Segura123')); // true

// Transformación de datos
const usuarios = [
  { nombre: 'Ana', edad: 25 },
  { nombre: 'Carlos', edad: 30 },
  { nombre: 'María', edad: 28 }
];

const obtenerNombres = pipe(
  filter(u => u.edad > 25),
  map(u => u.nombre.toUpperCase()),
  sort()
);

console.log(obtenerNombres(usuarios)); // ['CARLOS', 'MARÍA']

Librerías y Herramientas

Ecosistema FP en JavaScript:

Ramda

Librería FP con funciones currificadas

Lodash/fp

Versión FP de Lodash

React Hooks

Inspirados en principios FP

Redux

Flujo unidireccional inspirado en FP

// Ejemplo con Ramda
import R from 'ramda';

const usuarios = [
  { id: 1, nombre: 'Ana', edad: 25, activo: true },
  { id: 2, nombre: 'Carlos', edad: 30, activo: false },
  { id: 3, nombre: 'María', edad: 28, activo: true }
];

const nombresActivos = R.pipe(
  R.filter(R.prop('activo')),
  R.map(R.pipe(
    R.prop('nombre'),
    R.toUpper
  )),
  R.sortBy(R.identity)
)(usuarios);

// ['ANA', 'MARÍA']
DF

Sobre el autor

Functional Programming Advocate. Contribuidor a librerías como Ramda y autor de 'JavaScript Funcional en Profundidad'.