🎾 Racket — 1995

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

Racket empezó como un Scheme para enseñar y acabó convirtiéndose en algo que ningún otro lenguaje de esta lista es: una plataforma para construir lenguajes. Su lema —"un lenguaje de programación programable"— se toma literalmente: en Racket, crear un lenguaje nuevo con su propia sintaxis es una operación normal.

🎯 Por qué está en este programa

Racket es un primo de la familia Lisp (Atlas).

Aporta al programa la forma más extrema de metaprogramación (clase 122) y de lenguaje de dominio (clase 163): no ya macros que añaden construcciones, sino lenguajes completos con otra sintaxis y otra semántica, definidos como bibliotecas. Y aporta los contratos en ejecución (clase 118) en un lenguaje dinámico.

Año 1995 (como PLT Scheme); Racket desde 2010; Racket 8 actual
Autoría Matthias Felleisen y el grupo PLT (Northeastern, Utah, Brown, otras)
Familia Lisp; descendiente directo de Scheme
Paradigma Multiparadigma; funcional por defecto, con OO, lógico y lo que se defina
Tipado Dinámico, con contratos y con Typed Racket para tipado estático gradual
Memoria Recolección de basura
Ejecución Compilado a bytecode sobre Chez Scheme desde Racket 8
Estado 🟢 Vivo: enseñanza, investigación en lenguajes y proyectos propios

📜 Historia

PLT Scheme nació en 1995 con un objetivo docente: DrScheme —después DrRacket— era un entorno diseñado para principiantes, con niveles de lenguaje que iban activando características según avanzaba el curso, y con mensajes de error pensados para enseñar.

De ahí salió How to Design Programs (HtDP), un método de enseñanza de programación basado en recetas de diseño —del tipo de datos se deriva la forma de la función— que se usa en decenas de universidades y que es, en sí mismo, una aportación pedagógica seria.

Pero lo que convirtió a Racket en lo que es fue una decisión posterior: hacer del sistema de macros una plataforma para definir lenguajes enteros. En 2010 el cambio de nombre marcó ese giro, y hoy el primer renglón de un fichero Racket dice en qué lenguaje está escrito:

#lang racket          ; el lenguaje por defecto
#lang typed/racket     ; con tipos estáticos
#lang scribble/base     ; ← un lenguaje de DOCUMENTOS
#lang datalog            ; ← Datalog, dentro de Racket
#lang mi-lenguaje         ; ← el tuyo

Y todos interoperan, porque todos compilan al mismo núcleo.

🏭 Dónde vive hoy

🧠 Lo que enseña: definir lenguajes como bibliotecas

Este es el concepto, y no lo tiene ningún otro lenguaje de este Atlas con esta profundidad:

#lang racket

(provide (rename-out [mi-app #%app])    ; ← redefinir cómo funciona LA APLICACIÓN
         (except-out (all-from-out racket) #%app))

Se puede redefinir qué significa llamar a una función, qué significa un literal numérico, o cómo se lee el texto del fichero. Un #lang es un módulo que exporta el lector y las macros del lenguaje.

Y de ahí salen cosas como #lang scribble —donde el texto plano es lo normal y el código va marcado, al revés que en un lenguaje de programación— o #lang datalog, que es Datalog de verdad, con su semántica lógica, dentro del mismo sistema.

Es la clase 163 llevada al límite: en lugar de incrustar un lenguaje ajeno, el lenguaje anfitrión permite fabricar el incrustado.

Y la segunda aportación son los contratos (clase 118), que Racket implementa mejor que ningún otro lenguaje dinámico:

(provide (contract-out
          [dividir (-> number? (and/c number? (not/c zero?)) number?)]))

El contrato se comprueba en la frontera del módulo, en ejecución — y cuando falla, el mensaje dice quién tiene la culpa: si el que llamó pasó un argumento malo, o si la función devolvió algo que no debía.

Esa atribución de culpa es la aportación técnica: en un lenguaje dinámico, saber de qué lado de la frontera está el error es la mitad del diagnóstico (clase 137).

🔄 Lo que se ha modernizado

⚙️ Cómo se ejecuta hoy

racket main.rkt < entrada.txt        # ejecutar
raco test main.rkt                    # pruebas (clase 139)
raco exe main.rkt                      # ejecutable autocontenido (clase 174)
raco pkg install <paquete>

🧪 El programa de la clase 041 en Racket

Esta versión se escribe aquí y no está verificada en CI (clase 040).

#lang racket

(define campos (string-split (read-line)))
(define nums (map string->number campos))
(define total (* (first nums) (second nums) (- 1 (third nums))))

(printf "Total: ~a\n" (real->decimal-string total 2))

Lo que hay que ver.

📚 Fuentes y bibliografía


⏮️ Volver al Atlas · 🗂️ Todas las fichas · 🔗 Relacionadas: Scheme · Common Lisp · Clojure · Datalog