Colecciones, transformaciones y recursión en Clojure

En esta segunda semana de Clojure, dejamos atrás la parte más introductoria y entramos a una de las ideas más importantes del lenguaje: trabajar con colecciones de forma funcional.
Cuando empezamos a construir software real, casi todo gira alrededor de recibir datos, transformarlos, filtrarlos y combinarlos para obtener respuestas útiles. En Clojure, esto se hace con una gran claridad gracias a funciones como map, filter, reduce y a la forma natural de manipular maps, vectors, lists y sets.
Source Code: https://github.com/joedayz/clojure-senior-path/tree/week2
1) Las colecciones son el corazón de Clojure
Clojure está muy centrado en el trabajo con datos estructurados. Las colecciones más comunes son:
(def nums [1 2 3 4 5])
(def fruits '(:manzana :pera :uva))
(def user {:name "Ana" :age 30})
(def tags #{:backend :clojure :functional})
Cada una tiene un propósito diferente:
Vector:
[...]→ colección ordenadaLista:
'(...)→ estructura común en programación funcionalMap:
{...}→ pares clave/valorSet:
#{...}→ valores únicos
Esto es importante porque en proyectos reales no solo guardamos valores sueltos; normalmente trabajamos con listas de productos, usuarios, pedidos, métricas, clientes y estados.
2) Transformar datos con map
La función map aplica una operación a cada elemento de una colección.
(defn double-all
[numbers]
(map #(* 2 %) numbers))
Uso:
(double-all [1 2 3 4])
;; => (2 4 6 8)
Esto parece pequeño, pero es extremadamente útil. En aplicaciones reales, map te permite:
duplicar precios
convertir cadenas a mayúsculas
calcular impuestos
agregar metadata a cada registro
aplicar transformaciones a listas completas
La belleza de map es que expresa claramente: “aplica esta operación a cada elemento”.
3) Filtrar con filter
Cuando queremos quedarnos con los elementos que cumplen una condición, usamos filter.
(defn even-only [numbers]
(filter even? numbers))
Uso:
(even-only [123456])
;; => (2 4 6)
Este patrón es muy común en negocios y aplicaciones:
clientes activos
pedidos mayores a cierto monto
productos con precio superior a un umbral
usuarios con rol específico
filter no solo simplifica el código; también hace que el propósito sea más fácil de leer.
4) Reducir datos con reduce
reduce toma una colección y la combina en un solo valor. Es ideal para sumar, acumular, agrupar o construir resultados finales.
(defn sum-numbers [numbers]
(reduce +0 numbers))
Uso:
(sum-numbers [12345])
;; => 15
En proyectos reales, reduce se usa para:
sumar ventas
calcular totales
crear resúmenes por cliente
acumular contadores
generar reportes
Por ejemplo:
(defn total-sales [orders]
(reduce+ (map:totalorders)))
Aquí primero transformamos cada pedido a su total con map, y luego reducimos esa colección con +.
5) Trabajar con maps y datos de negocio
Los maps son probablemente la estructura más importante cuando modelamos información del negocio. Los usuarios, productos, pedidos y clientes se representan muy bien como maps.
(defn describe-user [{:keys [nameageemail]}]
(strname" tiene "age" años y su email es "email))
Uso:
(describe-user {:name"Ana":age30:email"ana@example.com"})
;; => "Ana tiene 30 años y su email es ana@example.com"
Con esto vemos algo muy útil: no escribimos mucho código para acceder a los datos, y el programa se vuelve mucho más legible.
También es común filtrar registros por una propiedad:
(defn active-users [users]
(filter:activeusers))
Cuando representas entidades como maps, te resulta mucho más fácil crear lógica de negocio clara y expresiva.
6) Recursión y cómo pensar en flujo de datos
Aunque Clojure ofrece herramientas muy poderosas para iterar, la recursión sigue siendo una pieza clave para entender cómo funciona la lógica funcional.
(defnsum-recursive [numbers]
(if (empty?numbers)
0 (+ (firstnumbers)
(sum-recursive (restnumbers)))))
La idea es simple:
revisamos el primer elemento
tomamos el resto de la colección
repetimos hasta llegar al caso base
Cuando la colección está vacía, la recursión termina.
Este tipo de ejemplo ayuda a internalizar la forma en que Clojure trata los datos: como flujo que se va consumiendo paso a paso, sin depender tanto de un estado mutable.
7) Pipelines de transformación
Una de las cosas más valiosas en Clojure es saber encadenar funciones para formar un pipeline claro.
(defnexpensive-items [products]
(->>products (filter #(> (:price%) 100))
(map:name)))
Esto significa:
tomar la colección de productos
filtrar solo los caros
mapear solo sus nombres
Eso es exactamente la mentalidad de Clojure: describir el flujo del dato de una manera muy legible y muy expresiva.
8) Por qué esta semana importa tanto
La semana 2 no trata solo de aprender funciones aisladas. Se trata de desarrollar una manera de pensar:
qué datos tengo
qué quiero transformar
qué condición necesito aplicar
qué resultado final necesito obtener
Esto es lo que hace que Clojure sea tan potente en proyectos reales.
Cuando entiendes map, filter y reduce, ya puedes:
sumar ventas
filtrar clientes activos
calcular promociones
generar reportes
transformar data de una API
normalizar información
preparar estructuras que luego usen otras partes del sistema
9) El siguiente paso
Esta semana nos pone en un nivel mucho más útil para el desarrollo real. Ya no solo estamos escribiendo funciones pequeñas; estamos manipulando datos con intención y claridad.
La clave es que cada una de estas herramientas no se usa de forma aislada. Se combinan. Se encadenan. Y eso es lo que hace que el código en Clojure sea tan elegante.
En la siguiente etapa, seguiremos avanzando hacia la organización de proyectos, pruebas y modelado de dominio, pero la base que aprendimos en esta semana será esencial para todo lo que venga después.
Si ya estás practicando con map, filter, reduce y recursión, entonces ya estás empezando a pensar como desarrollador funcional. Y esa es la parte más valiosa del aprendizaje.
Enjoy!
Joe




