JavaScript de Cero a Experto / JS funcional
Currying y aplicación parcial: argumentos por etapas
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:
// ✓ 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.