Scheme es un dialecto minimalista del lenguaje de programación Lisp, diseñado para facilitar un estilo de programación funcional mientras promueve una sintaxis simple y limpia. Se caracteriza por su uso de paréntesis, un poderoso sistema de macros y un fuerte énfasis en la recursión y los procedimientos de primera clase. El lenguaje fomenta un paradigma de programación funcional y admite múltiples técnicas de programación, incluyendo programación funcional, imperativa y lógica.
Scheme fue creado en la década de 1970 por Gerald Jay Sussman y Guy L. Steele Jr. en el Instituto Tecnológico de Massachusetts (MIT). Se desarrolló como un intento de simplificar y mejorar el lenguaje Lisp original, que había crecido en complejidad con el tiempo. La motivación detrás de Scheme era crear un lenguaje que fuera más fácil de implementar y enseñar, mientras que aún fuera lo suficientemente poderoso como para expresar ideas complejas.
A lo largo de los años, Scheme ha pasado por varias revisiones y esfuerzos de estandarización. Los estándares más notables son los RnRS (Informes Revisadosn sobre el Lenguaje Algorítmico Scheme), que formalizaron el lenguaje y sus características. Desde entonces, la comunidad de Scheme ha continuado desarrollando el lenguaje, dando lugar a nuevos estándares como R6RS y R7RS, que introdujeron nuevas características y mejoras.
Hasta ahora, Scheme sigue siendo popular en entornos académicos, particularmente en la educación en ciencias de la computación, debido a su elegancia y sintaxis limpia. Su influencia se puede ver en muchos lenguajes de programación y paradigmas modernos. Scheme a menudo se asocia con la comunidad de programación funcional y ha inspirado lenguajes como Clojure y Racket, que se basaron en sus principios y ampliaron sus capacidades.
Scheme utiliza una sintaxis completamente paréntesis donde el código se escribe en notación prefija; por ejemplo, una operación de suma se escribe como (+ 1 2)
.
Las funciones en Scheme son ciudadanos de primera clase, lo que significa que pueden ser pasadas como argumentos o devueltas de otras funciones. Ejemplo:
(define (make-adder x)
(lambda (y) (+ x y)))
(define add5 (make-adder 5))
(add5 10) ; devuelve 15
Scheme soporta la optimización de llamadas en cola, permitiendo que las funciones reutilicen el marco de pila actual para llamadas recursivas que ocurren en posición de cola, previniendo el desbordamiento de pila.
Scheme permite el uso de continuaciones, lo que habilita a los programadores a capturar el estado actual de la computación y manipular el flujo de control:
(call-with-current-continuation
(lambda (exit)
(exit 'done)))
Scheme tiene un poderoso sistema de macros que permite a los programadores crear extensiones sintácticas. Una macro simple se puede definir de la siguiente manera:
(define-syntax my-if
(syntax-rules ()
((_ test then else)
(if test then else))))
Scheme soporta la abstracción de datos a través de estructuras como listas, pares y funciones de orden superior, lo que permite una manipulación eficiente de datos.
Scheme emplea el alcance léxico, donde el alcance de una variable se determina por su ubicación física en el código fuente. Esto conduce a un comportamiento predecible respecto a los enlaces de variables.
Scheme es de tipado dinámico, permitiendo que las variables contengan valores de cualquier tipo sin necesidad de declaraciones de tipo explícitas.
Como un dialecto de Lisp, Scheme está optimizado para el procesamiento de listas, facilitando la realización de operaciones sobre listas:
(define my-list (list 1 2 3 4))
(car my-list) ; devuelve 1
(cdr my-list) ; devuelve (2 3 4)
Las funciones de Scheme pueden definirse recursivamente con posición de cola para optimizar el uso de memoria y el rendimiento. Por ejemplo:
(define (factorial n)
(define (fact-helper n acc)
(if (zero? n)
acc
(fact-helper (- n 1) (* n acc))))
(fact-helper n 1))
Las aplicaciones Scheme generalmente se pueden construir utilizando el entorno de ejecución de la implementación elegida. Por ejemplo, en Racket, puedes usar la herramienta de línea de comandos racket
para ejecutar archivos .rkt
o compilarlos en ejecutables.
Varios compiladores e intérpretes están disponibles para Scheme, incluyendo:
Scheme se utiliza ampliamente en el ámbito académico para enseñar principios de programación y como herramienta para la investigación en ciencias de la computación. Tiene aplicaciones en inteligencia artificial, diseño de lenguajes y scripting, así como en varios dominios que requieren computación simbólica o manipulación compleja de datos.
Ambos lenguajes soportan un estilo de programación funcional, pero Python enfatiza la legibilidad y simplicidad, mientras que Scheme se centra en expresiones poderosas y concisas. La sintaxis rica en paréntesis de Scheme puede verse como una barrera para los principiantes, mientras que la sintaxis basada en indentación de Python es generalmente más accesible.
JavaScript también soporta programación funcional y tiene funciones de primera clase. Sin embargo, JavaScript tiene un sistema de objetos basado en prototipos, mientras que Scheme se basa en paradigmas funcionales. El sistema de macros de Scheme ofrece capacidades que no están presentes en JavaScript.
C es un lenguaje de bajo nivel y tipado estático diseñado para programación de sistemas, mientras que Scheme es de alto nivel y tipado dinámico. C se centra en el rendimiento y la manipulación a nivel de hardware, mientras que Scheme enfatiza la abstracción y los aspectos teóricos de la computación.
Ambos lenguajes están arraigados en la programación funcional. Haskell utiliza un sistema de tipos más rígido y soporta evaluación perezosa, mientras que el tipado dinámico y la evaluación ansiosa de Scheme permiten una programación más flexible a costa de un rendimiento algo menor.
Ruby es un lenguaje de programación orientado a objetos que mezcla características de programación funcional, mientras que Scheme es puramente funcional. La sintaxis de Ruby es más verbosa, mientras que la simplicidad de Scheme proviene de su diseño minimalista.
La traducción de código Scheme a otros lenguajes puede facilitarse mediante herramientas que entiendan tanto la sintaxis de Scheme como el lenguaje de destino. Algunas herramientas útiles de traducción de código de fuente a fuente incluyen:
Chicken Scheme proporciona un compilador que puede traducir código Scheme a C, lo que hace posible aprovechar bibliotecas de C y crear ejecutables eficientes.
Racket, un derivado de Scheme, tiene capacidades integradas para transformar y compilar código en JavaScript, facilitando el despliegue de aplicaciones web.
Gambit Scheme puede compilar código Scheme en C y ejecutables nativos, proporcionando opciones de traducción eficientes para aplicaciones críticas en rendimiento.