Racket desde cero: el Lisp que te va a enamorar
Racket Meetup San Luis Potosí
"Lisp is worth learning for the profound enlightenment experience you will have when you finally get it." — Eric S. Raymond
Bienvenidx. Hoy vas a aprender un lenguaje de la familia más antigua y más extraña de la programación. Un lenguaje donde el código es un dato, los paréntesis son estructura pura, y los programas se escriben a sí mismos. No exageramos: al final de este tutorial vas a escribir tu propia sintaxis.
Un poco de historia (o: por qué esto existe desde 1958)
Lisp nació en 1958, inventado por John McCarthy en el MIT. Para dar contexto: es el segundo lenguaje de alto nivel más antiguo que sigue vivo (solo Fortran, de 1957, le gana por un año). Python nació en 1991. JavaScript en 1995. Lisp les lleva más de 30 años de ventaja... y varias de las ideas que hoy consideramos "modernas" nacieron ahí:
- Recolección de basura (garbage collection) — inventada para Lisp.
- Funciones de primera clase — pasar funciones como argumentos, hoy normal en todos lados.
- El REPL — ese ciclo interactivo de leer-evaluar-imprimir que hoy tiene Python, Node, Julia... nació en Lisp.
- Condicionales como expresiones — el
ifque devuelve un valor. - Homoiconicidad — el código es una estructura de datos del propio lenguaje. Esta es la grande. Volvemos a ella al final.
Lisp fue durante décadas el lenguaje de la inteligencia artificial. En los 70s y 80s existieron computadoras físicas diseñadas para ejecutar Lisp directamente: las Lisp Machines de Symbolics y LMI. Luego vino el "invierno de la IA", los fondos se secaron, y Lisp pasó de estrella a lenguaje de culto.
Pero los cultos interesantes no mueren: mutan.
De Lisp a Scheme a Racket
En 1975, Gerald Sussman y Guy Steele crearon Scheme: un Lisp minimalista, elegante, casi matemático. Scheme se volvió el lenguaje favorito de la academia para enseñar a programar (el legendario libro SICP Structure and Interpretation of Computer Programs está escrito en Scheme).
En 1995, el grupo de Matthias Felleisen creó PLT Scheme, un Scheme diseñado para la educación y la investigación en lenguajes de programación. En 2010 se renombró a Racket, y hoy es mucho más que un Scheme: es un lenguaje para crear lenguajes. Su lema no oficial es language-oriented programming: si tu problema necesita su propio lenguaje, Racket te deja construirlo en una tarde.
| Año | Evento |
|---|---|
| 1958 | McCarthy inventa Lisp en el MIT |
| 1975 | Sussman y Steele crean Scheme |
| 1984 | Se estandariza Common Lisp |
| 1995 | Nace PLT Scheme (hoy Racket) |
| 2007 | Nace Clojure (Lisp sobre la JVM) |
| 2010 | PLT Scheme se renombra a Racket |
| Hoy | Tú, en este meetup, escribiendo paréntesis |
¿Y quién usa Lisp hoy?
Más gente de la que crees:
- Clojure se usa en producción en bancos, aerolíneas y startups (Nubank, el banco digital más grande de América Latina, corre sobre Clojure).
- Common Lisp (con el compilador SBCL) sigue vivo en sistemas expertos, planificación de vuelos (ITA Software, comprada por Google, motorizaba Google Flights) y computación científica.
- Emacs Lisp millones de personas ejecutan Lisp todos los días sin saberlo, porque su editor es un intérprete de Lisp.
- Guile/Guix una distribución completa de Linux configurada 100% en Scheme.
- Racket tiene su propia conferencia anual (RacketCon), una comunidad académica y artística vibrante, y se usa para investigación en lenguajes, verificación formal (Rosette), tipografía y publicación (Pollen), y educación en todo el mundo.
- Y hay Lisps nuevos naciendo todo el tiempo: Fennel (Lisp que compila a Lua, popular para videojuegos), Janet, Hy (Lisp sobre Python)...
Lisp no es una pieza de museo. Es un río subterráneo que lleva 67 años alimentando todo lo demás.
🎪 Easter egg para los fans de TADC: en The Amazing Digital Circus (episodio 8, "hjsakldfhl"), cuando Kinger abre la terminal para intentar resetear a Caine, se ve que Caine una IA creativa creada en 1996 está programado en Lisp. El archivo se llama literalmente
Caine-core.lisp.1 O sea: cuando termines este tutorial vas a saber el lenguaje en el que está escrito el ringmaster del circo digital. Úsalo con más responsabilidad que C&A.
Instalación (5 minutos)
- Ve a https://racket-lang.org
- Descarga el instalador para tu sistema (Linux, macOS, Windows).
- Abre DrRacket, el entorno que viene incluido.
DrRacket tiene dos áreas: arriba escribes tus definiciones (tu programa), abajo tienes el REPL para experimentar en vivo. En la primera línea del área de definiciones escribe:
#lang racket
Esa línea le dice a Racket qué lenguaje estás usando (recuerda: Racket es una fábrica de lenguajes, así que hay que elegir uno).
Si prefieres la terminal: el comando racket te da un REPL y raco es el gestor de paquetes y herramientas.
Tu primer contacto: todo es una expresión
En el REPL, prueba:
> (+ 1 2)
3
> (* 3 (+ 2 2))
12
> (string-append "hola " "meetup")
"hola meetup"
La regla de Lisp cabe en una línea:
Todo es
(operador argumento1 argumento2 ...). Siempre. Sin excepciones.
No hay precedencia de operadores que memorizar, no hay sintaxis especial para nada. (+ 1 2) suma. (if ...) decide. (define ...) nombra. Los paréntesis que asustan al principio son, en realidad, la ausencia total de reglas arbitrarias. En una semana ni los ves.2
Definiciones y funciones
#lang racket
(define pi-aprox 3.14159)
(define (area-circulo r)
(* pi-aprox r r))
(area-circulo 2) ; => 12.56636
definecon un nombre crea una constante.definecon(nombre argumentos...)crea una función.- Los comentarios empiezan con
;.
Las funciones anónimas usan lambda (sí, esa lambda el cálculo lambda de Church de los años 30 es el abuelo teórico de todo esto):
(lambda (x) (* x x)) ; una función sin nombre
((lambda (x) (* x x)) 5) ; => 25, aplicada directamente
Listas: el corazón de Lisp
Lisp significa LISt Processing. Las listas son la estructura fundamental:
(list 1 2 3) ; => '(1 2 3)
'(1 2 3) ; lo mismo, "citada" (quote)
(first '(1 2 3)) ; => 1
(rest '(1 2 3)) ; => '(2 3)
(cons 0 '(1 2 3)) ; => '(0 1 2 3)
(length '(a b c)) ; => 3
Fíjate en la comilla '. Le dice a Racket: no evalúes esto, es un dato. Guarda ese detalle: es la puerta a la magia final.
Funciones de orden superior
Aquí Racket brilla. Pasar funciones a otras funciones es lo más natural del mundo:
(map (lambda (x) (* x x)) '(1 2 3 4 5))
; => '(1 4 9 16 25)
(filter even? '(1 2 3 4 5 6))
; => '(2 4 6)
(foldl + 0 '(1 2 3 4 5))
; => 15
map transforma, filter selecciona, foldl acumula. Con esas tres funciones resuelves el 80% de los problemas de listas sin escribir un solo for.
Recursión: pensar en espiral
En Lisp no piensas "repite N veces", piensas "¿cuál es el caso base y cómo me acerco a él?":
(define (factorial n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
(factorial 5) ; => 120
Y para que se vea bonito en el meetup, dibujemos algo. Racket trae librerías gráficas incluidas:
#lang racket
(require 2htdp/image)
(define (sierpinski nivel)
(if (= nivel 0)
(triangle 8 "solid" "purple")
(let ([t (sierpinski (- nivel 1))])
(above t (beside t t)))))
(sierpinski 6)
Pégalo en DrRacket, presiona Run, y mira aparecer el triángulo de Sierpinski en tu pantalla.
El gran final: código que escribe código
Recuerda la comilla ': convierte código en datos. Observa:
'(+ 1 2) ; => la LISTA (+ 1 2), no el número 3
(first '(+ 1 2)) ; => el símbolo +
(eval '(+ 1 2)) ; => 3. Acabas de evaluar un dato como código.
Tu programa es una lista. Puedes construir listas. Ergo: puedes construir programas con programas. Esto es la homoiconicidad, y es la razón por la que Lisp tiene macros de verdad no macros de texto como en C, sino funciones que reciben código y devuelven código, antes de ejecutar nada.
¿Racket no tiene un while? Inventémoslo:
(define-syntax-rule (mientras condicion cuerpo ...)
(let loop ()
(when condicion
cuerpo ...
(loop))))
(define contador 0)
(mientras (< contador 5)
(displayln contador)
(set! contador (+ contador 1)))
Acabas de extender el lenguaje. No pediste permiso, no esperaste a la versión 4.0 de Racket, no escribiste un parser. En la mayoría de los lenguajes, la sintaxis es propiedad del comité que lo diseña. En Lisp, la sintaxis es tuya.
Por eso Alan Kay llamó a Lisp "the Maxwell's equations of software": un núcleo diminuto del que se deriva todo lo demás.
¿Y ahora qué?
- How to Design Programs — el libro con el que se diseñó Racket, gratis en línea.
- The Racket Guide — documentación oficial, de las mejores que existen.
- Beautiful Racket — aprende a crear tus propios lenguajes.
- SICP — el clásico de clásicos, si quieres la iluminación completa.
- Y por supuesto: el Racket Meetup SLP. Trae tus paréntesis, tus dudas y tus fractales.
El chiste es viejo pero cierto: "Lisp no es un lenguaje, es un material de construcción." Bienvenidx a la obra.
Hecho con 🖤 y paréntesis balanceados para la comunidad de San Luis Potosí.
Y la referencia es históricamente impecable: Lisp fue creado precisamente para investigar IA capaz de abstraer y crear cosas por sí misma. Para una empresa ficticia construyendo una IA creativa en 1996, Lisp era exactamente la elección correcta. Alguien en Glitch Productions hizo su tarea.↩
En serio. Pregúntale a cualquier lisper. Los paréntesis desaparecen y solo queda el árbol.↩