Para quienes no están familiarizados con ella, Lisp puede parecer un lenguaje de programación peculiar. Su código está plagado de paréntesis. Algunos incluso bromean diciendo que el nombre significa "Lots of Isolated Silly Parentheses" (Muchos Paréntesis Aislados y Tontos). Sin embargo, esta descripción es inexacta. Lisp significa Procesamiento de Listas (List Processing), y el lenguaje opera sobre estructuras de datos denominadas listas, encerradas entre paréntesis. Estos paréntesis delimitan el inicio y el final de una lista. A menudo, una lista está precedida por un apóstrofo (').
1.1 Listas en Lisp
Una lista en Lisp tiene la siguiente apariencia: '(clavel rosal lirio tulipán). Esta lista está precedida por una comilla simple. También podría escribirse de manera más convencional:
'(clavel
rosal
lirio
tulipán)
Los elementos de esta lista son nombres de flores, separados por espacios y encerrados entre paréntesis.
Números y listas anidadas
Las listas pueden contener números. Considere esta lista: (* 7 3). Tiene el símbolo de multiplicación '*' seguido de los números '7' y '3'.
En Lisp, tanto los datos como los programas se representan de la misma manera: como listas de palabras, números u otras listas, separados por espacios y rodeados por paréntesis. Esto permite que un programa pueda tratarse como datos de otro, una característica muy poderosa.
Aquí hay una lista que contiene otra lista en su interior:
'(esta lista contiene (una sublista dentro))
Esta lista se compone de las palabras 'esta', 'lista', 'contiene' y la lista '(una sublista dentro)'.
1.1.1 Átomos en Lisp
Las palabras individuales en una lista se denominan átomos. El término proviene de su significado histórico de "indivisible". En el contexto de Lisp, los átomos (símbolos, números, cadenas) no pueden descomponerse en partes más pequeñas con significado dentro del programa. Las listas, por el contrario, sí pueden dividirse.
Los átomos están separados por espacios dentro de las listas y pueden adyacer a los paréntesis. Técnicamente, una lista está formada por paréntesis que encierran átomos u otras listas, separados por espacios. Una lista puede contener un solo átomos o estar vacía. Una lista vacía se escribe así: () y se considera tanto un átomo como una lista.
La representación impresa de átomos y listas se llama expresión simbólica o s-expresión. Por ejemplo:
'(este ejemplo incluye "texto entre comillas")
Todo el texto entre comillas dobles, incluyendo puntuación y espacios, forma un único átomo llamado cadena (string).
1.1.2 Espaciado en listas
La cantidad exacta de espacios en blanco dentro de una lista no es significativa para el lenguaje Lisp. Estas dos representaciones son idénticas:
'(este ejemplo
se ve así)
'(este ejemplo se ve así)
Los saltos de línea y espacios extra se usan para que las listas sean más legibles para los humanos. El intérprete de Lisp los ignora, siempre que exista al menos un espacio para separar los átomos.
1.1.3 Emacs y la entrada de listas
Cuando se trabaja en Emacs Lisp, el editor proporciona facilidades como la sangría automática (con TAB) y el resaltado de paréntesis coincidentes, lo que ayuda enormemente a escribir código estructurado.
1.2 Ejecución de un programa
Cualquier lista en Lisp es potencialmente un programa ejecutable. Al evaluarse, el intérprete hará una de tres cosas: devolver la lista tal cual (si está citada), generar un error, o tratar el primer elemento como un comando (una función) a ejecutar.
La comilla simple ' se llama "quote" e impide la evaluación. Evaluemos un ejemplo:
(* 5 3)
Si posiciona el cursor tras el paréntesis final y presiona C-x C-e, verá el resultado 15 en el área de eco. Ahora, con una lista citada:
'(esto es una lista citada)
La evaluación devolverá la lista misma.
El comando C-x C-e invoca a eval-last-sexp, que significa "evaluar la última expresión simbólica".
1.3 Generación de mensajes de error
Evaluar una lista no citada cuyo primer elemento no es una función válida genera un error. Esto es útil para aprender. Intentemos:
(esto no es una función)
Esto abrirá un búfer de *Backtrace* (rastreo hacia atrás) mostrando el error. El intérprete intentó buscar una definición de función para el símbolo esto, pero no la encontró. El mensaje clave es: void-function: esto.
El mensaje void-function indica que el símbolo no tiene una definición de función asociada. Para salir del depurador, escriba q en el búfer *Backtrace*.
1.4 Nombres de símbolos y definiciones de funciones
Un símbolo como + no es intrínsecamente una instrucción; es un nombre que puede estar vinculado a una definición de función. Un mismo conjunto de instrucciones (definición de función) puede tener varios nombres. Sin embargo, un símbolo solo puede tener una definición de función vinculada en un momento dado.
1.5 El intérprete de Lisp
El proceso del intérprete al evaluar una lista es: si está citada, la devuelve; si no, mira el primer elemento, busca su definición de función y ejecuta las instrucciones correspondientes. Si no hay definición, produce un error.
Formas especiales y macros
Existen algunas funciones inusuales llamadas "formas especiales" (como if) y "macros" (como when) que no siguen exactamente el patrón estándar de evaluación. Las macros transforman expresiones antes de evaluarlas. Para el principiante, la distinción no es crucial al principio.
1.5.1 Compilación de bytecode
El código Lisp puede compilarse a "bytecode", una forma no legible pero más rápida de ejecución. Los archivos compilados suelen tener extensión .elc. Para la mayoría de las personalizaciones, trabajar con código fuente (.el) es suficiente.
1.6 Evaluación
El proceso por el cual el intérprete determina el valor de una expresión se llama evaluación. El resultado más común es que el intérprete devuelva un valor, posiblemente con efectos secundarios (como imprimir texto o mover el cursor).
1.6.1 Evaluación de listas internas
Cuando hay listas anidadas, el intérprete evalúa primero la lista más interna, y su resultado se usa como argumento para la lista externa. Ejemplo:
(+ 4 (* 2 5))
Primero se evalúa (* 2 5) obteniendo 10, luego se evalúa (+ 4 10), obteniendo 14.
1.7 Variables
Un símbolo puede estar vinculado tanto a una definición de función como a un valor. El valor es lo que puede cambiar, de ahí el término "variable". Un símbolo con un valor se llama variable.
Ejemplo de variable: column-width
La variable column-width tiene un valor numérico en cada búfer de Emacs. Para verlo, evalúe el símbolo solo:
column-width
Si su valor es 70, verá 70 en el área de eco.
1.7.1 Error por símbolo sin función
Si intenta usar una variable como función, obtendrá un error void-function.
1.7.2 Error por símbolo sin valor
Si evalúa un símbolo que no tiene un valor asignado, obtendrá un error void-variable.
1.8 Argumentos
Los argumentos son los datos que se pasan a una función. En (+ 4 3), los números 4 y 3 son los argumentos de la función +.
1.8.1 Tipos de datos de los argumentos
Cada función espera ciertos tipos de datos. + espera números. La función concat espera cadenas.
(concat "amigo" "mío")
Resultado: "amigomío".
La función substring toma una cadena y dos números.
(substring "El veloz zorro" 8 13)
Resultado: "zorro". Los índices comienzan en 0.
1.8.2 Argumentos como variables o listas
Un argumento puede ser una variable o una lista que devuelve un valor al evaluarse.
(+ 10 column-width)
Si column-width vale 70, el resultado es 80.
1.8.3 Número variable de argumentos
Algunas funciones, como + o concat, aceptan un número variable de argumentos.
(+) ;; ⇒ 0
(+ 5) ;; ⇒ 5
(+ 1 2 3) ;; ⇒ 6
1.8.4 Uso de tipos de objetos erróneos
Pasar un argumento del tipo incorrecto genera un error. Por ejemplo:
(+ 2 'hola)
El intérprete intentará sumar el número 2 al valor del símbolo 'hola', que no es un número, y producirá un error wrong-type-argument.
1.8.5 La función message
La función message imprime texto en el área de eco. Puede incluir especificadores de formato como %s (para cadenas) y %d (para enteros).
(message "El búfer actual se llama: %s" (buffer-name))
(message "El ancho de columna es %d" column-width)
1.9 Asignación de valores a variables
La forma principal de asignar un valor a una variable es con la forma especial setq.
1.9.1 Uso de setq
Para asignar el valor de la variable colores a una lista:
(setq colores '(rojo verde azul))
<p>La evaluación devuelve la lista asignada, y como efecto secundario, vincula el símbolo <code>colores</code> a esa lista.</p>
<p><code>setq</code> permite múltiples asignaciones en una sola expresión:</p>
<code>(setq arboles '(pino abedul roble)
aves '(canario periquito))
</code>
<h3>1.10 Resumen</h3>
<p>Los conceptos clave son: los programas Lisp están compuestos por expresiones (listas o átomos); las listas tienen estructura jerárquica; los átomos representan datos indivisibles; las variables almacenan valores; las funciones reciben argumentos y producen resultados; y la evaluación es el proceso central del lenguaje.</p>
<h3>1.11 Ejercicios</h3>
<p>Practique lo aprendido:</p>
- Genere un mensaje de error evaluando un símbolo sin paréntesis que no tenga valor.
- Genere un mensaje de error evaluando un símbolo entre paréntesis que no tenga definición de función.
- Cree un contador que se incremente en tres en lugar de uno.
- Escriba una expresión que, al evaluarse, imprima su propio código en el área de eco (usando una cita).