Scheme

Imagina que no hay ciclos
en tu programación
no existen for ni while
tan sólo recursión.
Imagina a la gente
entre paréntesis…

Este es un fragmento de una canción que me encontré en un foro de discusión para el lenguaje Scheme (en Usenet), junto con la instrucción de que debía cantarse con la melodía de la canción Imagine de John Lennon. Era mediados de los noventa. Me encontraba aprendiendo y recolectando información sobre lenguajes funcionales en general, y de Scheme en particular para un proyecto educativo de mi campus en el Tec de Monterrey. Esa canción, junto con el contenido exaltado y a veces autocomplaciente de algunas entradas en el foro, formó mi primera impresión del lenguaje, la cual no difería mucho de la opinión de la mayoría de los programadores de los paradigmas clásicos: parecía un lenguaje académico, orientado a estudiantes de posgrado en inteligencia artificial. Sólo que en mi institución estábamos pensando adoptarlo, no como un lenguaje para materias avanzadas, sino para los cursos de computación básica, en lugar de C o el cada vez más popular Java. Las discusiones no se hicieron esperar. Recibimos una gran cantidad de cejas levantadas, pero en mi departamento éramos un pequeño grupo con espíritu visionario y mucha curiosidad; de modo que le dimos luz verde al proyecto. Scheme era un lenguaje definitivamente extraño. Su estructura sintáctica se basaba en expresiones funcionales escritas en notación prefija, rodeada por paréntesis. De modo que para expresar, por ejemplo: la suma entre dos números, se debía escribir la siguiente sentencia: (+ 5 7)

La construcción de expresiones más complejas generaba entonces una cantidad de paréntesis que de inmediato se convirtió en el blanco de las bromas entre profesores y alumnos. Sin embargo, descubrí que, enunciando las expresiones de manera funcional, la sintaxis resultaba intuitiva. Así,

(raizCuadrada (+ (cuadrado a) (cuadrado b)))

se leía como “la raíz cuadrada de la suma del cuadrado de a con el cuadrado de b”, con los paréntesis definiendo de manera exacta el significado de la expresión. El corazón del lenguaje era la definición de nuevas funciones por medio del operador lambda. De este modo, la función cuadrado se declaraba como:

(define cuadrado (λ(x) (* x x))) 1

Fue aquí que decidí que me agradaba el lenguaje. No había tipos de datos (o más bien, para los puristas, sólo hay tipos débiles), lo que permitía escribir funciones interesantes a tan solo horas de conocer el lenguaje. Los números eran verdaderamente polimórficos, permitiendo operaciones entre enteros y reales sin distinción, sin riesgo de overflow. Existía una única estructura de datos: la lista. Y como estructura de control, se utilizaba la recursividad. Comenzamos a utilizar Scheme en los cursos de computación básica, y para mitad del semestre los alumnos podían resolver problemas típicos de un curso de estructuras de datos. Inventé ejercicios interesantes para ellos, fascinado por la libertad que el lenguaje me daba para enseñar algoritmos y lógica de programación.

Sin embargo, resultó que estábamos adelantados a nuestro tiempo. Algoritmos elegantes o no, los estudiantes extrañaban la deslumbrante interfaz visual de Java. Se preguntaban el por qué aprendían un lenguaje que no existía en la industria. Y definitivamente, odiaban los paréntesis. El escepticismo ganó, dimos por terminado el proyecto y Java ocupó su lugar como el lenguaje reinante en el aula.

Para entonces yo estaba fascinado con el lenguaje. La razón era que, desde su diseño, incorporaba características que facilitaban la labor del programador. Por ejemplo, los lenguajes funcionales ya incluían el uso de algoritmos de recolección de basura y la pre-compilación de funciones (el antecedente de la máquina virtual) desde antes de que Java popularizara los conceptos. Además, estaba la alta capacidad de abstracción de estos lenguajes: aprendí, por ejemplo, que podía definir funciones que operaban sobre listas de tamaño infinito, que las funciones mismas no eran diferentes de los tipos de datos básicos, y que podían utilizarse como entradas o salidas de otra función. De modo que lo utilicé en mis proyectos durante mis estudios de doctorado, creando soluciones elegantes que sorprendían a mis compañeros por su simplicidad y corto tiempo de desarrollo. Esto era un triunfo pequeño dado que, mi uso del lenguaje había regresado al ambiente académico.

Diez años después, la industria de desarrollo ha pasado por la programación orientada a objetos, la programación por eventos y la programación orientada a servicios. ¿Cuál es el siguiente paso en la evolución de los lenguajes? Al parecer, es la aparición de lenguajes multi-paradigma, que incorporan finalmente el paradigma funcional, el orientado a objetos y el imperativo. Me parece interesante que la comunidad en general esté adoptando estos lenguajes, y que finalmente el paradigma funcional pudiera salir del ámbito académico. Python es uno de estos lenguajes, con una popularidad en aumento. La plataforma .NET contará con F#, y para el desarrollo web se tiene Perl 6. Todos estos lenguajes están basados en Haskell, un sucesor de Scheme.

Me siento optimista de que puedo volver a programar en un lenguaje funcional. Y esta vez, con una sintaxis menos extraña: Haskell no tiene paréntesis.

Para el lector curioso, esta expresión se lee como “define cuadrado como la función que recibe el parámetro x, y regresa la multiplicación de x por x”.

Acerca del autor
Dr. Raúl A. Trejo es profesor investigador del Instituto Tecnológico y de Estudios Superiores de Monterrey, campus Estado de México. Su área de especialidad es la inteligencia artificial, con una particular pasión por la programación. Conoció el paradigma funcional con Basic y Pascal, se graduó en objetos con Eiffel, Ada y Java, y probó la lógica de Prolog. Pero siempre admiró la elegancia de Scheme: (define infinito (λ ( ) ((λ (f) (f f)) (λ (f) (f f))))). El significado de esta expresión se encuentra en: tech-o-potamus.blogspot.com