Racket (lenguaje de programación)
Racket es un lenguaje de programación de amplio espectro de la familia de Lisp y Scheme. Es multiparadigma así como de propósito general. Uno de sus principales objetivos tras su diseño es posibilitar la creación de nuevos lenguajes o dialectos.[1] El lenguaje es usado en una variedad de entornos tales como scripting, enseñanza en ingeniería informática o la investigación.
Racket | ||
---|---|---|
Desarrollador(es) | ||
PLT Inc https://racket-lang.org/ | ||
Información general | ||
Extensiones comunes |
.rkt , .rktl , .rktd , .scrbl , .plt , .ss , .scm | |
Apareció en | 1994 | |
Sistema de tipos | Dinámico, Fuerte, Estático | |
Influido por | Scheme | |
Sistema operativo | Multiplataforma | |
Licencia | LGPL | |
La plataforma nos ofrece la herramienta DrRacket, un entorno de desarrollo integrado programado en Racket, que nos facilitará la tarea de programar en Racket. También nos ofrece raco, un herramienta para la línea de comandos que nos permitirá instalar paquetes o compilar librerías.[2]
La plataforma se adhiere a la iniciativa Software libre, y está liberada bajo una licencia LGPL.
Historia
En enero de 1994, PLT (fundada por Matthias Felleisen) decidió crear un entorno de programación pedagógico basado en Scheme, y se creó MrEd, la primera máquina virtual para Racket. Más tarde desarrollaron DrScheme, con PLT Scheme como principal lenguaje de desarrollo. En los siguientes años se fueron añadiendo una serie de características que lo consolidaron como entorno de desarrollo pedagógico.
El primer grupo de actualizaciones de PLT Scheme facilitaron la creación de programas de gran escala al introducir módulos y clases. El sistema de clases obtuvo nuevas características, como las interfaces o la herencia múltiple. La siguiente gran actualización modificó el sistema de módulos alrededor de las macros, separando la ejecución de la compilación. Esto permitió a los desarrolladores ampliar la plataforma mediante el uso de extensiones en distintos lenguajes, formado una "torre de lenguajes".[3] Versiones posteriores introdujeron soporte para Unicode, refinamientos del sistema de clases y se mejoró el rendimiento del lenguaje mediante el uso de un compilador JIT. En la última actualización bajo el nombre de PLT Scheme se introdujo la etiqueta #lang
para especificar el lenguaje de un módulo, pares inmutables, listas, soporte para paralelismo y dialectos de tipado estático.[4]
El 7 de junio de 2010, coincidiendo con la salida de la versión 5.0, se le cambió el nombre a PTL Scheme por Racket, así como el nombre de DrScheme a DrRacket.[5] La interfaz gráfica, que estaba escrita en C++, fue reescrita en Racket usando toolkits nativos en cada plataforma.[6]
Características
Racket es altamente flexible, incluso sin el uso de dialectos. Características tales como el uso de macros, módulos, clausuras, recursión en cola, y mucho más, le permiten ser usado para la realización de todo tipo de tareas, desde generación de gráficos a web scrapers. Además, el potente sistema de macros permite a los desarrolladores controlar todos los aspectos de un lenguaje, una de las principales metas tras su diseño. El framework viene con un gestor de paquetes llamado PLaneT integrado con el sistema de módulos, lo que permite a los usuarios importar y usar librerías de terceros de forma totalmente transparente.[7]
Extensiones del lenguaje
La principal característica de Racket es la capacidad de crear y extender nuevos lenguajes. Esto es posible gracias a una serie de componentes:
- Un sistema de módulos capaz de enlazar código y manejar espacios de nombres
- Un sistema de macros que permite la creación de nuevas formas sintácticas
- Un sistema de tiempo de ejecución que ofrece muchas opciones a los nuevos lenguajes
- Formas de especificar e implementar analizadores sintácticos para dichos lenguajes.
El primer punto, el sistema de módulos, es el encargado de hacer posible muchas de estas características, permite el uso de una gran cantidad de módulos conjuntamente, donde cada uno de ellos puede estar escrito en un lenguaje distinto.
Implementar un nuevo lenguaje en Racket es tan sencillo que muchos de ellos tienen muy pocos usos, ya que fueron concebidos con un objetivo muy concreto.
Typed Racket
Typed Racket, definido por la etiqueta #lang typed/racket
es una variante de Racket con tipado estático, lo que permite a los programas madurar, ya que el tipado estático puede ayudar en el mantenimiento de una aplicación de gran tamaño. Entre los objetivos de este dialecto se encuentra el permitir la escritura de código más expresivo. Otra característica es la inclusión de código tipado en programas no tipados, lo que permitiría llamar a módulos escritos en Typed Racket.
El siguiente fragmento de código define una lista cuyos elementos son del tipo Str-or-Num
(definido previamente).
#lang typed/racket
(define-type Str-or-Num (U String Number))
(: tog ((Listof Str-or-Num) -> String))
(define (tog l)
(apply string-append (filter string? l)))
(tog (list 5 "hello " 1/2 "world" (sqrt -1)))
Lazy Racket
Otro ejemplo de las posibilidades que ofrece Racket es la implementación de evaluación perezosa (del inglés lazy evaluation), no estando esta característica en el núcleo principal del lenguaje. El siguiente ejemplo muestra como se definiría una lista de Fibonacci infinita cuyos elementos solo son calculados cuando es necesario.[8]
#lang lazy
;; Definimos la lista
(define fibs
(list* 1 1 (map + fibs (cdr fibs))))
;; Accedemos al elemento numero 1000
(print (list-ref fibs 1000))
Scribble
Scribble es la familia de dialectos de Racket usados para escribir prosa. Su principal eso es el de actuar como sistema de documentación de Racket, pero puede ser usado para mucho más, como la escritura de libros o artículos. Cada uno de los dialectos es usado para diferentes propósitos.[9]
El lenguaje trabaja en modo texto por defecto (todo lo que escribamos formará parte del fichero final), y utiliza el carácter @
para hacer llamadas a las distintas funciones ofrecidas. En el siguiente ejemplo podemos ver el uso de la función title
, así como una muestra del uso del modo texto. Si guardamos el archivo como raton.scrbl
y ejecutamos scribble --pdf raton.scrbl
generaremos un fichero pdf con los contenidos especificados.
#lang scribble/base
@title{Sobre los hábitos de un ratón}
Si le das una galletita a un ratón, te pedirá un vaso de leche.
Tiempo de ejecución
Racket ofrece una variedad de características orientadas a la mejora del rendimiento en tiempo de ejecución.
Recolector de basura
Racket puede ser usado con tres recolectores de basura distintos:
- Boehm, un recolector de basura conservador, fue el primero en ser utilizado. Puede presentar problemas para programas que son ejecutados durante de forma continua, como los servidores web, ya que las pequeñas fugas de memoria se pueden ir acumulando con el tiempo.
- SenoraGC, una alternativa, también en la familia de los recolectores conservadores, usada principalmente para depurar programas y encontrar fugas de memoria.
- El gestor de memoria en movimiento (también conocido como "3m", del inglés moving memory manager), que ha sido el recolector por defecto desde el 2007. Se trata de un recolector preciso, por lo que no presenta algunos de los problemas de las alternativas.
Interfaz de sistema
Racket posee una interfaz de sistema con entrada salida asíncrona no bloqueante, hilos de ejecución verdes, canales de sincronización, semáforos, subprocesos, y sockets TCP. Esto nos permite realizar todo tipo de accesos a las funciones ofrecidas por el sistema operativo. Por ejemplo, en el siguiente ejemplo lanzamos un proceso que maneja conexiones entrantes en el puerto 12345:
#lang racket
(define listener (tcp-listen 12345))
(let echo-server ()
;; Creamos el servidor
(define-values (in out) (tcp-accept listener))
;; Lanzamos un nuevo hilo por cada conexión entrante
(thread (λ () (copy-port in out) (close-output-port out)))
;; Y volvemos a lanzar el servidor, a la espera de una nueva conexión
(echo-server))
Programación Web y de Redes
Gracias a la extensibilidad de Racket encontramos que cierto tipo de tareas resultan extremadamente sencillas. Por ejemplo, el siguiente programa hace uso del dialecto web-server/insta
para crear un servidor web en solo dos líneas:
#lang web-server/insta
(define (start request)
(response/xexpr '(html (body "¡Hola Mundo!"))))
Además, Racket incluye todas las funciones necesarias para crear scrapers o arañas web. El siguiente ejemplo obtiene los resultados de Google dada una cadena de búsqueda:
#lang racket
(require net/url net/uri-codec)
(define (let-me-google-that-for-you str)
(let* ([g "http://www.google.com/search?q="]
[u (string-append g (uri-encode str))]
[rx #rx"(?<=<h3 class=\"r\">).*?(?=</h3>)"])
(regexp-match* rx (get-pure-port (string->url u)))))
Gráficos
En Racket las imágenes son variables, al igual que los son los números o las cadenas de texto, por lo que podemos crear programas que generen imágenes, y el editor nos las mostrará. Para hacer esto posible tenemos una variedad de librerías gráficas en Racket que nos permiten generar imágenes a través de las funciones que nos ofrece. Por ejemplo, la librería 2htdp/image
nos permite generar imágenes sin mucha complicación, por lo que es usada en entornos educativos. El siguiente ejemplo genera un Triángulo de Sierpinski de nivel 8:
#lang racket
(require 2htdp/image)
(let sierpinski ([n 8])
(if (zero? n)
(triangle 2 'solid 'red)
(let ([t (sierpinski (- n 1))])
(freeze (above t (beside t t))))))
Si enfocamos hacia el mundo académico, podemos encontrar la librería plot
, que nos permite generar gráficas. Esta librería nos permite exportar nuestros resultados como archivos PNG, PDF, PostScript y SVG además de mostrarlos en el editor.
Interfaces Gráficas
Una de las librerías ofrecidas por Racket nos permite la creación de interfaces gráficas, ya sea a mano posicionando línea a línea los elementos, o mediante el uso de editores presentes en PLaneT. La librería está implementada mediante el uso de llamadas a la API nativa en Windows, con Cocoa en Mac OS X, y con Gtk en Linux. El siguiente ejemplo genera una ventana con una serie de botones con números, y el programa nos hace adivinar cual de ellos es el correcto:
#lang racket/gui
(define secret (random 5))
(define f (new frame% [label "Adivina el número"])) ; Ventana principal
(define t (new message% [parent f]
[label "¿Puedes adivinar el numero que estoy pensando?"]))
(define p (new horizontal-pane% [parent f])) ; Contenedor horizontal
(define ((make-check i) btn evt)
(message-box "." (cond [(< i secret) "Demasiado pequeño"]
[(> i secret) "Demasiado grande"]
[else "¡Exacto!"]))
(when (= i secret) (send f show #f))) ; Se ha adivinado, por lo que cerramos la ventana
(for ([i (in-range 10)]) ; Creamos los botones
(make-object button% (format "~a" i) p (make-check i)))
(send f show #t) ; Mostramos la ventana, comenzando la aplicación
Referencias
- Tobin-Hochstadt, S.; St-Amour, V.; Culpepper, R.; Flatt, M.; Felleisen, M. (2011). «Languages as Libraries». Programming Language Design and Implementation.
- Welcome to Racket, introducción a la plataforma.
- Flatt, M. (2002). «Composable and Compilable Macros». International Conference on Functional Programming.
- PLT Scheme version 4.0 Archivado el 23 de julio de 2014 en Wayback Machine., notas de publicación de la versión 4.0
- PLT Scheme is a Racket, notas sobre el cambio de nombre
- Rebuilding Racket’s Graphics Layer Archivado el 22 de junio de 2014 en Wayback Machine., la reescritura de la capa gráfica
- PLaneT: Automatic Package Distribution, documentación de PLaneT
- Chacón Sartori, Camilo. Computación y programación funcional : introducción al cálculo lambda y la programación funcional usando Racket y Python. [Barcelona]: Marcombo. ISBN 8426732437.
- Scribble: The Racket Documentation Tool, "Scribble, la herramienta de codumentación de Racket"