CodeForge

JavaScript de Cero a Experto / JS funcional

Currying y aplicación parcial: argumentos por etapas

Teoría20 min20 XP

Llevas dos lecciones escribiendo (config) => (dato) => ... sin ponerle nombre. Hoy lo bautizamos: currying — partir una función para recibir sus argumentos por etapas — y su uso práctico, la aplicación parcial: configurar hoy, ejecutar después. Es la última pieza técnica del módulo, y la que hace que todo lo anterior encaje con clic.

La masa lista en la nevera

Mira lo que pasó en el map final: menos10 espera UN argumento y map entrega uno por elemento — encaje perfecto, sin arrow envolvente. Las funciones de un solo argumento son las piezas de Lego universales del estilo funcional: todo conecta con todo. Y no hay magia nueva: la etapa fijada vive en la mochila (clausura), exactamente como en tus fábricas — currying ES el patrón de fábrica, sistematizado.

La regla de diseño: configuración primero, dato después

Para que una función curry sirva en pipes, el ORDEN de las etapas importa: primero lo que se conoce temprano y cambia poco (la configuración), de último lo que fluye (el dato). Compara:

orden.js
// ✓ configuración → dato: parcializa natural
const filtrar = (criterio) => (lista) => lista.filter(criterio);
const enMoneda = (locale, moneda) => (valor) =>
valor.toLocaleString(locale, {
  style: "currency", currency: moneda, maximumFractionDigits: 0,
});

// se fijan una vez, arriba del proyecto...
const enCOP = enMoneda("es-CO", "COP");
const soloCaros = filtrar((g) => g.valor > 20000);

// ...y las piezas listas alimentan cualquier línea
const informeCaros = pipe(soloCaros, totalizar, enCOP);

Con el orden invertido — (lista) => (criterio) => ... — la aplicación parcial fijaría el DATO y dejaría pendiente la configuración: exactamente lo contrario de lo útil. Cuando diseñes fábricas, pregúntate qué se sabe primero; eso va en la primera etapa. (Fíjate también en enMoneda: una etapa puede recibir VARIOS argumentos — currying no exige de a uno; exige etapas con sentido.)

Nota honesta doble: en JavaScript cotidiano se usa este "currying suave" — arrows anidadas donde aporta, y funciones normales donde no; el curry automático total (curry(fn) que convierte cualquier función) vive en librerías como Ramda y rara vez lo necesitarás. Y no todo debe ser curry: suma(a, b) de dos argumentos que siempre llegan juntos está perfecta como está. El criterio: ¿hay una etapa que se REPITE con el mismo valor? Curry. ¿No? Función normal y a otra cosa.

Tienes const porCategoria = (lista) => (categoria) => lista.filter((g) => g.categoria === categoria) y quieres fabricar soloComida para usarla en varios pipes sobre listas distintas. No hay forma elegante. ¿Cuál es el problema de diseño?

Mini-reto

Tu caja de piezas configurables: 1) entre = (min, max) => (valor) => ... (una etapa de dos argumentos) y pruébala con filter sobre los valores de tus gastos; 2) redondearA = (multiplo) => (valor) => ... (con Math.round(valor / multiplo) * multiplo) y fabrica alMil = redondearA(1000); 3) el combo final: una línea pipe que filtre gastos entre 5000 y 50000, totalice, redondee al mil y formatee con tu enCOP parcializado. Cuatro piezas curry, una frase de código.

Qué sigue

Kit completo: pureza, inmutabilidad, fábricas, pipes y currying. El reto del módulo los funde en una sola obra — el motor de reportes de "Mi Bolsillo": una biblioteca de estaciones puras y configurables que produce informes por combinación, con el original siempre intacto. El estilo funcional, demostrado con plata.