🍀 Clojure — 2007

⬅️ Atlas · 🗂️ Todas las fichas · 📚 Índice de clases

Clojure es un Lisp moderno sobre la JVM, diseñado por una sola persona con una tesis muy clara: el problema del software no es la complejidad del dominio, sino la complejidad que añadimos nosotros — y la mayor parte viene del estado mutable. Todo el lenguaje es la consecuencia de esa idea.

🎯 Por qué está en este programa

Clojure es un primo de la familia JVM (Atlas) y también de la familia Lisp: comparte máquina virtual con Java y modelo con Common Lisp.

Aporta al programa la inmutabilidad como decisión total (clase 102) y las estructuras de datos persistentes que la hacen viable; y aporta un modelo de concurrencia distinto de todos los del curso: identidades separadas de valores, con atom y con memoria transaccional (clases 135 y 136).

Año 2007; 1.0 en 2009; 1.12 actual
Autoría Rich Hickey, tras dos años y medio de trabajo en solitario
Familia Lisp sobre JVM; con influencia de Common Lisp, Scheme, Haskell y ML
Paradigma Funcional, con datos inmutables; sin orientación a objetos
Tipado Dinámico y fuerte; con spec y malli para contratos en ejecución
Memoria La de la JVM
Ejecución Bytecode JVM; también ClojureScript (a JS) y ClojureCLR
Estado 🟢 Nicho sólido y estable; comunidad pequeña y muy influyente

📜 Historia

Rich Hickey llevaba veinte años programando en C++, Java y .NET cuando, en 2005, se tomó un paréntesis de dos años y medio —financiado con sus ahorros— para diseñar el lenguaje que quería usar.

El resultado, publicado en 2007, parte de un diagnóstico que expuso en su charla Simple Made Easy, una de las más citadas de la historia de la disciplina:

Confundimos "simple" con "fácil". Simple es no entrelazado; fácil es familiar. El estado mutable compartido es lo contrario de simple, aunque nos resulte facilísimo.

Y de ahí las decisiones:

ClojureScript (2011) llevó el lenguaje al navegador, y de ahí salió Reagent/Re-frame, cuya arquitectura de estado influyó en el ecosistema React (clase 169).

Y su comunidad tiene una particularidad que merece nombrarse: es de las más estables de esta lista. El lenguaje cambia poco y a propósito, y la compatibilidad hacia atrás se cuida — la misma disciplina de Go y Tcl (clase 154).

🏭 Dónde vive hoy

🧠 Lo que enseña: valores, identidades y tiempo

Esta es la idea que hay que llevarse, y no la tiene ningún otro lenguaje del curso:

(def cuenta (atom {:saldo 100}))       ; una IDENTIDAD que apunta a un VALOR inmutable

(swap! cuenta update :saldo + 50)       ; ← cambia a QUÉ VALOR apunta, atómicamente
@cuenta                                  ; {:saldo 150}

El mapa {:saldo 100} nunca cambia. Lo que cambia es a qué valor apunta cuenta, y ese cambio es atómico y sin cerrojos — con comparación e intercambio por debajo.

Y de ahí sale una propiedad enorme para la clase 136: no hay carreras de datos sobre los valores, porque los valores no se pueden modificar. Solo hay que coordinar las identidades, que son pocas y están declaradas.

Y las estructuras persistentes son lo que lo hace asequible:

(def a [1 2 3])
(def b (conj a 4))     ; b es nuevo... y COMPARTE la estructura interna de a

No se copia el vector. Por debajo hay un árbol con factor de ramificación 32, y añadir un elemento crea unos pocos nodos nuevos. Es la técnica que la clase 102 describe y que también usan Scala y las bibliotecas inmutables de JavaScript.

Y hay una tercera idea, muy práctica, que Clojure defiende: usar mapas en lugar de definir clases.

{:nombre "Ana" :edad 30}      ; ← no hace falta declarar un tipo Persona

Los datos son datos, y las funciones genéricas de la biblioteca —get, assoc, update, merge, select-keys— funcionan sobre todos ellos. Es lo contrario del modelado con clases, y clojure.spec añade la validación donde hace falta en lugar de en todas partes.

🔄 Lo que se ha modernizado

⚙️ Cómo se ejecuta hoy

clojure -M main.clj < entrada.txt      # el comando de la clase 041
bb main.clj                             # babashka: arranque en milisegundos

clj -X:test                              # pruebas
clj-kondo --lint src                      # análisis estático, muy bueno (clase 146)

🧪 El programa de la clase 041 en Clojure

(require '[clojure.string :as str])

(let [[precio cantidad descuento] (map read-string (str/split (read-line) #" "))
      total (* precio cantidad (- 1 descuento))]
  (println (format "Total: %.2f" (double total))))

Lo que hay que ver.

📚 Fuentes y bibliografía


⏮️ Volver al Atlas · 🗂️ Todas las fichas · 🔗 Relacionadas: Common Lisp · Scheme · Java · Scala · Elixir