LISP 1.3 A manera de introducción: El lenguaje de programación Lisp nació en 1960, su nombre deriva de 'list processing', es decir 'procesamiento de listas', pero también puede entenderse como 'list programming' o sea 'programación mediante listas'. Diseñado para procesamiento de datos simbólicos y cualquier otro campo de IA (inteligencia artificial). Lisp trabaja con expresiones 'S', es decir expresiones simbólicas de longitud indefinida y una estructura del tipo ramas de árbol. Inventado por John McCarthy en 1958 mientras estaba en el Instituto de Tecnología de Massachusetts (MIT), es el segundo lenguaje más antiguo en el mundo de la programación, el primero es el Fortran. Con el tiempo se formaría toda una familia de dialectos Lisp compartiendo su tan particular sintaxis. Actualmente los dialectos más usados son Common Lisp y Scheme. La primera versión más ampliamente difundada fue LISP 1.5, seguida del Stanford LISP 1.6. La versión para Spectrum, Lisp 1.3, puede considerarse un sub set del Stanford LISP con el cual comparte mucho, tanto en los nombres de primitivcas como sintacticamente, pero un sub set limitado en comparación. Spec-lisp posee en cambio comandos gráficos tipo tortuga. Ninguna versión conocida de Lisp posee esta caracteristica salvo excepciones como el Emac-Lisp para máquinas Macintosh. Para la creación de este manual, debido a que no poseo el original, ni lo he encontrado, me vi obligado a usar la información de los siguientes textos: The Elements of Artificial Intelligence (An Introduction using LISP), LISP 1.5 Programmers Manual, SAILON-28.6, On lisp, varias páginas WEB y el libro 7 de Informatica aplicada: Juegos inteligentes en microordenadores. Para cargarlo basta hacer 'Load ""' y una vez hecho eso, aparece el siguiente mensaje: SpecLisp 1.3 © 1983 Serious Software Made in England * Ahora Lisp está listo y esperando que uno ingrese algo. Sintaxis: (primitiva [argumento(s)]) Primitivas del Lisp: Add1, And, Apply, Atom, Border, Car, Cadr, Cdr, Cddr, Cls, Cond, Cons, Cset, Csetq, De, Diff, Div, Eq, Equal, Eval, Exit, Function, Fwd, Get, Greaterp, Gc, Ink, Left, Lessp, List, Load, Member, Minusp, Nill, Not, Null, Numberp, Oblist, Or, Paper, Pch, Pend, Penu, Plus, Print, Progn, Prt, Putprop, Quote, Right, Read, Rem, Remprop, Reverse, Rnd, Rplaca, Rplacd, Save, Set, Setq, Stack, Sub1, Times, Trace, Verify, While, Zerop. Acepta los siguientes símbolos como válidos: ; ? @ : < > ^ _ = y £. Dan error de formato numérico ilegal los siguientes símbolos: / ' ! " * => $ <= # y %. No hay modo de tipear los siguientes símbolos al no haber modo EXT: ~ | [ { } ] © y \. La coma es también aceptada como separador de elementos al igual que el espacio. Ejemplo: '1,2,3' equivale a '1 2 3'. No admite las teclas de cursores, así que es imposible corregir o editar una línea de texto, excepto borrando con DELETE hasta llegar a la letra que uno quiera corregir. Sólo admite el cursor izquierda pero para provocar la acción [CANCEL]. - Ocultar texto citado - Una lista Lisp se conforma de: valores 'apval', expresiones 'expr', subrutinas 'subr', funciones lambda, y pname (nombres de primitivas). Evaluadores: EVAL (evaluate) sintaxis: (eval x) Simplemente evalúa x y lo ejecuta si es válido, de lo contrario dará error. Ejemplos: (eval 1) - es aceptado pero: (eval (1 3 4)) - busca evaluar el primer elemento de la lista y genera el error '1 IS NOT A FUNCTION' en cambio: (eval (car (1 3)) - ejecutará la función car si existiese y evalúa su sintaxis. QUOTE sintaxis: (quote x) forma especial que permite ingresar una expresión x sin que Lisp la evalúe. Quote solo admite un argumento que puede ser un átomo, un número o una lista. Ejemplo: (eval (quote (1 3 4))) - evalúa y devuelve como válido (1 3 4) Nota: Otras versiones de Lisp aceptan la forma abreviada 'x, no admitida por Spectrum Lisp. SET sintaxis: (set v x) donde v = un símbolo y x = el valor a poner. Set evalúa siempre v. Es equivalente a LET v=x del Basic. Ejemplo: (set var 1) - dará error 'var IS AN UNBOUND VARIABLE' pero: (set (quote var) 1) - será admitido y hará var = 1. SETQ sintaxis: (setq v x) equivale a (set (quote v) x) Ejemplos: (setq xs (quote alfa)) - crea la variable xs con el valor 'alfa' (set xs 65) - ya que xs contiene a alfa, set creará la variable alfa = 65. (setq xs 65) - en cambio reescribirá xs y lo convertirá en numérico. APPLY sintaxis: (apply f la) permite aplicar una función f a un argumento la. Ejemplo: (apply plus 2 3) - da el error de argumentos incorrectos. (apply (quote plus)(pend 2 3)) - ejecuta la función y devuelve 5. FUNCTION sintaxis: (function s) donde s = una función definida por el usuario. devuelve una lista conteniendo todos los datos que conforman la función creada por uno. Ejemplo: (function fact) - la función debe existir, de lo contrario devolverá error. Manipulación de estructuras de listas: CAR sintaxis: (car l) devuelve el primer elemento de la lista l. Da error si l no es una lista. Car es por "Contents of the Address part of Register number". Equivale a First del lenguaje LOGO. Ejemplos: (car (1 2 3)) - devuelve error pero: (car (quote (1 2 3))) y (car (pend 1 2 3)) sí lo son. Dando como resultado 1. CDR sintaxis: (cdr l) Decrementa y genera una lista conteniendo todos los elementos de 'l' menos el primero. Cdr es por "Contents of the Decrement part of Register number". Equivale a BF (butfirst) del LOGO. Ejemplo: (cdr (quote (1 2 3 4))) - devuelve (2 3 4) como resultado. CADR sintaxis: (cadr x) equivale a hacer (car (cdr x)) Ejemplo: (cadr (pend 1 2 3 4 5)) - dará 2 como resultado. CDDR sintaxis: (cddr x) equivale a hacer (cdr (cdr x)) Ejemplo: (cddr (pend 1 2 3 4 5)) - dará (3 4 5) como resultado. CONS (construct) sintaxis: (cons n l) genera una lista añadiendo n al comienzo de la lista l dada. Ejemplos: (cons 1 2) - es aceptado y da 1.2 en respuesta, pero: (cons 1 2 3 4) devueve error pues admite sólo dos argumentos. En cambio: (cons 1 (cons 2 (cons 3 (cons 4 nil)))) - devuelve (1 2 3 4) LIST sintaxis: (list l) genera una lista uniendo las listas que se le pasen como argumento l. ejemplo: (list (quote (1 3))(quote (4 5 6))(quote alfa)) genera la lista: ((1 3) (4 5 6) alfa) RPLACA sintaxis: (rplaca x y) devuelve x pero reemplazando su primer elemento por y. Como resultado x es modificado directamente en la memoria. Ejemplo: sean las listas a = (1 2 3 4) y b = (6 7 8 9) (rplaca a b) - hace a = ((6 7 8 9) 2 3 4) es equivalente a hacer: (setq a (cons b (cdr a))) RPLACD sintaxis: (rplacd x y) Similar a rplaca. Modifica x reemplazando el decremento de x por y. Ejemplo: (rplacd b a) - hace b = (6 1 2 3 4) Esto equivale a hacer: (setq b (cons (car b) a)) REVERSE sintaxis: (reverse ls) pone en orden inverso todos los elementos componentes de una lista ls. Ejemplo: (reverse (pend 1 3 5 7)) - devuelve (7 5 3 1) Funciones aritméticas: PLUS sintaxis: (plus x y) suma dos valores. Un tercer valor provoca mensaje de error. (+ x1 ... xn) es admitido por otros Lisp, no por Spec-lisp. DIFF (difference) sintaxis: (diff x y) resta dos valores dando su diferencia. (- x1 ... xn) es admitido por otros Lisp, no por Spec-lisp. TIMES sintaxis: (times x y) permite la multiplicacion de dos valores. (* x1 ... xn) es admitido por otros Lisp, no por Spec-lisp. DIV sintaxis: (div x y) hace la división entera de dos valores. (/ x1 ... xn) es admitido por otros Lisp, no por Spec-lisp. REM (remainder) sintaxis: (rem x y) Equivale al operador MOD de otros lenguajes y da el resto de la division entera. ADD1 sintaxis: (add1 x) Añade o suma un 1 al valor x. Equivale a (1+ x) de otros Lisp. SUB1 sintaxis: (sub1 x) Substrae o resta 1 al valor x Equivale a (1- x) de otros Lisp. Predicados: ATOM sintaxis: (atom x) comprueba si el argumento x es o no un átomo. ZEROP sintaxis: (zerop x) Verifica si x es cero. NUMBERP sintaxis: (numberp x) comprueba si el argumento x es o no un numero. MINUSP sintaxis: (minusp x) Da T si x es un número negativo. GREATERP sintaxis: (greaterp x y) Devuelve T si x es mayor que y. En caso contrario da Nil. Equivale a (> x y) de otros Lisp. LESSP sintaxis: (lessp x y) Devuelve T si x es menor que y. Nil si no. Equivale a (< x y) de otros Lisp. NULL sintaxis: (null x) Da T si x es una lista vacía (). Nil para cualquier otro caso. EQ sintaxis: (eq x y) Como equal. Da T, pero sólo si 'x' e 'y' son átomos literales. Dará Nil si son números o datos no atómicos. Ejemplos: (eq 1 1) - devuelve nil. (eq a b) - da error si a y b no son átomos previamente definidas. (eq (quote alfa)(quote alfa)) - devuelve T. EQUAL sintaxis: (equal x y) Devuelve T si x es igual a y, independientemente de si es átomo o número. Equivale a (= x y) de otros Lisp. Algunas versiones sin embargo limitan '=' a valores numéricos, dando error con cualquier otro tipo de dato. MEMBER sintaxis: (member x ls) Verifica si el átomo x pertenece o no a la lista ls. Da T en caso de que sí sea miembro y Nil si no lo es. Operadores lógicos: NOT sintaxis: (not x) niega el argumento x. AND sintaxis: (and x y) Da T si ambos argumentos son verdaderos, Nil en caso contrario. OR sintaxis: (or x y) Da T si al menos uno de los argumentos es verdadero. Control: COND (condition) sintaxis: (cond (x1 y1)(x2 y2)...(xx yy)) donde x = la condicion a evaluar, y = la acción a tomar o resultado a dar. Los argumentos de cond son llamados cláusulas y consisten de listas de dos elementos. Ejemplo: (cond (nil 1)(t 2)(t 3)) - dará 2 como resultado. (cond ((read)(print 1))((read)(print 2))) - imprimirá 1 o 2, incluso ambos, dependiendo de lo que el usuario ingrese, si es () para ambos no dará nada. PROGN (progresion) sintaxis: (progn [n]) Acepta n argumentos y devuelve el valor de la última evaluación tras evaluarlos todos. Da Nil si no tiene ningún argumento. El primer argumento debe ser un símbolo. Ejemplo: (progn (x)(setq x 10)(add1 4)) - da 5, el valor de la última expresión. (progn nil 1 (print (quote No)) (print (quote locales)) (setq x (add1 4)) ) - ejecutará los print y devolverá 5 pero ignorará 'setq x' y no le dará valor. WHILE sintaxis: (while c (a1...ax)) donde c = la condicion a evaluar, a = la acción a tomar. Lleva a cabo x acciones mientras se cumpla la condición dada. Ejemplo: (while (read) (print (quote ok?))) - termina al tipear () DE (define) sintaxis: (de nf (p1...px)(a1)(a2)...(ax)) donde: nf =nombre de función o procedimiento a definir p = parámetro(s) a = acción a llevar a cabo permite la definición de nuevos procedimientos o funciones que se añadirán a la librería de primitivas originales del Lisp y serán traados e invocados del mismo modo. Equivale a (defun ...) de otros Lisp. Ejemplo: una función factorial con recursión. (de factorial (n) (cond ((equal n 0) 1) (t (times n (factorial (diff n 1) ))) )) Definidores de propiedades: Lisp ofrece la posibilidad de crear listas asociativas, las cuales consisten en listas de listas, siendo una la propiedad y la otra el dato asociado a esa propiedad. CSET sintaxis: (cset v x) como set, pero para valores constantes y en algunas versiones de lisp se usa para añadir un valor x a una lista de propiedades v. Cset evalúa siempre sus argumentos. CSETQ sintaxis: (csetq v x) equivale a (cset (quote v) x). Una constante creada por cset/csetq no puede ser modificada por set o setq, solo por otra orden cset/csetq. Una variable set puede en cambio ser modificada por cset. Ejemplo: (csetq carro (quote b)) - inicializa la lista de propiedades con un dato inicial cualquiera, en este caso: b. PUTPROP sintaxis: (putprop n w p) donde n = nombre del símbolo o lista de propiedades w = el elemento a añadir p = el nombre de la propiedad a crear añade un elemento w a la lista de propiedades n, y si ya existiese una, la reemplaza. Ejemplo: (putprop carro (quote verde)(quote color)) (putprop carro (quote seat)(quote marca)) (putprop carro 127 (quote tipo)) esto le da a 'carro' las propiedades: (color verde) (marca seat) y (tipo 127). En otros lisp en cambio la sintaxis es (putprop 'carro 'color 'verde). Nota: otras versiones de lisp permiten ingresar los datos del sigte. modo: (setq carro '((color verde)(marca seat)(tipo 127))) GET sintaxis: (get n p) busca y muestra la propiedad 'p' en la lista de propiedades 'n'. Da nil si no hubiera ninguna, o si se tipea una propiedad inexistente. Ejemplos: (get carro (quote color)) - devuelve 'verde', pero: (get carro (quote llanta)) - dará nil si no se ha añadido antes con putprop. Nota: algunos Lisp carecen de la primitiva Putprop pero tienen en cambio: (setf (get 'x 'w) y) REMPROP sintaxis: (remprop n p) remueve una propiedad p de una lista de propiedades n. Ejemplo: (remprop carro (quote tipo)) - da t si la propiedad existe, nil si no. Entrada/salida: READ sintaxis: (read) Lisp espera a que se ingrese un dato por teclado seguido de ENTER. PRINT sintaxis: (print x) evalua el argumento 'x' y lo imprime en una línea aparte. Otras versiones admiten terpri, prin1 y princ, las cuales son inexistentes en Spec-lisp. PRT sintaxis: (prt) hace que todo cuanto se escriba, aparezca por la impresora en vez de por la pantalla, hasta que uno tipee "(exit)". SAVE sintaxis: (save n) Salva en casete la información bajo el nombre n. LOAD sintaxis: (load [n]) Carga en memoria los programas salvados en el casete. Si no se da un nombre, carga el primer archivo que encuentre. VERIFY sintaxis: (verify [n]) verifica que los datos se salvaron correctamente comparandolos con lo existente en la memoria RAM. Otros comandos y funciones: TRACE sintaxis: (trace [x]) Es una utilidad 'debugger'. Ayuda a la depuración de las funciones que uno define, permitiendo el seguimiento de su ejecución paso a paso. El primer trace que se tipee activa el rastreo, basta dar otro trace para desactivar su actividad. NILL sintaxis: (nill) Lisp no admite nil como orden directa o función, pero sí nill. GC (Garbage collector) sintaxis: (gc) libera el espacio de trabajo para las variables, procedimientos y ejecución de programas. Equivale a Recycle de LOGO. OBLIST sintaxis: (oblist) muestra una lista de todas las palabras reservadas del LISP, además de su dirección en memoria. También muestra las variables y funciones que uno crea. EXIT sintaxis: (exit) Interrumpe cualquier evaluación en curso. RND sintaxis: (rnd) da un valor aleatorio de tipo entero. PCH sintaxis: (pch x) imprime el código ascii correspondiente a x cuando es usado directamente. Devuelve x. Equivale a la función (tyo x) de otros lisp. STACK sintaxis: (stack x) donde x = una posición de memoria. Muestra el mensaje que aparece cuando se carga el Lisp por primera vez, luego de borrar la pantalla y todos los procedimientos y variables que existían en la memoria. Color y gráficos de tortuga: CLS sintaxis: (cls) limpia la pantalla igual que el CLS del Basic. PAPER sintaxis: (paper x) donde x = un valor de 0 al 7 para color, 8 transparencia y 9 contraste. Da color al fondo de la pantalla. INK sintaxis: (ink x) establece el color de la tinta en primer plano. BORDER sintaxis: (border x) establece el color del contorno de la pantalla como su equivalente en Basic. FWD (forward) sintaxis: (fwd x) donde x = un argumento numérico ya sea positivo o negativo. Devuelve x. Hace que la pluma de dibujo avance o retroceda (+/-)x pasos. El punto inicial es el mismo del Spectrum. (fwd 50) a partir de ese punto, es igual que hacer en Basic: DRAW 0,50. Fwd al igual que FD en LOGO usa coord. relativas en vez de absolutas. Requiere de Left y right para girar su curso. LEFT sintaxis: (left x) donde x = un número entero positivo tomado como ángulo de 0 a 360. Devuelve x. Le da a la pluma de dibujo un giro en dirección hacia la izquierda. RIGHT sintaxis: (right x) Como LEFT, pero girando hacia la derecha. También devuelve x. PENU sintaxis: (penu [x]) Alza la pluma de dibujo y devuelve la lista x dada como argumento. Sin argumentos da nil. Debe tener un argumeto para activarse. Ejemplo> (penu 1) - Fwd ya no dibujará nada. PEND sintaxis: (pend [x]) baja la pluma de dibujo y genera una lista x igual que penu. Sin argumentos devuelve nil. Como penu, pend también necesita al menos un argumento. Ejemplo> (pend 1) - permite a Fwd dibujar. (progn 1 (cls)(pend 1)(right 45)(fwd 100)) - dibuja una diagonal. (progn 1 (cls)(penu 1)(right 45)(fwd 100)) - mueve el cursor sin dibujar. Nota: ya que pend y penu devuelven el argumento como lista pueden usarse de la misma forma que quote para la gran mayoría de casos. Por ejemplo: (pend amigo mio) es equivalente a (quote (amigo mio)). Mensajes de error: PNAME PROPERTY NOT FOUND - propiedad del pname no encontrada ATOM OR - atomo o ... ILLEGAL NUMBER FORMAT - formato numérico ilegal FOUND - ... encontrado '(' EXPECTED - se esperaba un '(' ARITHMETIC OVERFLOW - se ha dado o calculado un valor fuera del rango de (+/-)32767 IS NOT A FUNCTION - ... no es una función ARE INCORRECT ARGUMENTS - los argumentos son incorrectos CAN'T TAKE CAR OF - No se puede hacer un car de ... CAN'T TAKE CDR OF - No se puede hacer un cdr de ... IS NOT SYMBOLIC - ... no es simbólico. Se da siempre que los argumento no cumplan la sintaxis. IS AN UNBOUND VARIABLE - ... no es un valor o variable reconocido IS NOT A NUMBER - ... no es un número [WAITING FOR GARBAGE COLLECTOR] - [esperando para el recolectado del desecho] [DELETE ATOMS TO FREE MEMORY] - [eliminando átomos para liberar memoria] [EXIT] - [Salir] IS NOT A FILE NAME - ... no es un nombre de archivo [CANCEL] - [Cancelar] [WAITING FOR COMPACTER] - [esperando para la compactación] IS TOO LARGE AN ANGLE - ... es un ángulo demasiado grande Francisco León zx_if1@hotmail.com