SlideShare une entreprise Scribd logo
1  sur  37
Télécharger pour lire hors ligne
ESCUELA POLITÉCNICA NACIONAL
DEPARTAMENTO DE INFORMÁTICA Y CIENCIAS
DE LA COMPUTACIÓN
PROGRAMACIÓN EN LISP
NIVEL BÁSICO
Hugo A. Banda Gamboa PhD, MSc.
2003
PRESENTACIÓN
Este manual de programación utilizando el lenguaje LISP, fue
desarrollado como una guía para mis estudiantes de la materia
Sistemas Inteligentes, que se dicta en el Programa de
Ingeniería en Sistemas Informáticos y de Computación de la
Escuela Politécnica Nacional. Básicamente, es una condensación
del libro clásico LISP, de Patrick Hendry Winston y Berthold
Klaus Paul Horn. También se incluyen aportes de otras obras
consultadas, que se indican en la sección BIBLIOGRAFÍA, y
experiencias recogidas durante 14 semestres que he dictado esta
materia. Espero que esta obra cumpla con su propósito de
incentivar al estudio y al trabajo experimental en las técnicas
y aplicaciones de la inteligencia artificial, utilizando LISP.
La referencia al interprete LISP y los ejemplos han sido
desarrollados utilizando el producto ALLEGRO CL for WINDOWS,
Version 5.0 Professional, de la casa:
Franz Inc.
1995 University Avenue,
Berkeley CA 94704, USA.
Para los estudiantes que estén interesados en obtener una
versión limitada del Allegro CL, en forma gratuita, pueden
hacerlo de la página WWW que mantiene Franz Inc. Su dirección
es:
http://www.franz.com
Finalmente, deseo dejar constancia de mi agradecimiento a mi
familia, Paty y Huguito, quienes generosamente me dieron su
apoyo para la realización de esta obra.
Quito, junio de 2003
Atentamente,
Hugo A. Banda Gamboa, PhD, MSc..
Profesor Principal
Departamento de Informática y Ciencias de la Computación
ESCUELA POLITÉCNICA NACIONAL
Quito - Ecuador
SISTEMAS DE INTELIGENCIA ARTIFICIAL PROGRAMACIÓN EN LISP
CONTENIDO
1. INTRODUCCIÓN ....................................................................................................................................... 1
2. TIPOS DE DATOS...................................................................................................................................... 1
3. INTERACCIÓN CON EL INTÉRPRETE LISP...................................................................................... 2
4. PRINCIPALES FUNCIONES PRIMITIVAS .......................................................................................... 3
4.1 SETF .................................................................................................................................................... 4
4.2 FIRST (CAR)....................................................................................................................................... 4
4.3 REST (CDR) ........................................................................................................................................ 4
4.4 NTHCDR ............................................................................................................................................. 4
4.5 BUTLAST............................................................................................................................................ 5
4.6 LAST.................................................................................................................................................... 5
4.7 LENGTH Y REVERSE........................................................................................................................ 5
4.8 CONS................................................................................................................................................... 5
4.9 APPEND .............................................................................................................................................. 6
4.10 LIST ..................................................................................................................................................... 6
4.11 REMOVE............................................................................................................................................. 6
4.12 ASSOC................................................................................................................................................. 6
4.13 SUMA, RESTA, PRODUCTO Y DIVISIÓN ...................................................................................... 7
4.14 FLOAT................................................................................................................................................. 7
4.15 ROUND................................................................................................................................................ 8
4.16 TRUNCATE ........................................................................................................................................ 8
4.17 REM..................................................................................................................................................... 8
4.18 MAX Y MIN......................................................................................................................................... 8
4.19 EXPT.................................................................................................................................................... 9
4.20 SQRT.................................................................................................................................................... 9
4.21 ABS...................................................................................................................................................... 9
5. DEFINICIÓN DE PROCEDIMIENTOS Y LIGADURA........................................................................ 9
5.1 DEFUN .............................................................................................................................................. 10
5.2 LET .................................................................................................................................................... 10
5.3 LET* .................................................................................................................................................. 11
6. PREDICADOS Y CONDICIONALES.................................................................................................... 11
6.1 =, EQ, EQL Y EQUAL....................................................................................................................... 11
6.2 MEMBER........................................................................................................................................... 12
6.3 ATOM, NUMBERP, SYMBOLP Y LISTP ....................................................................................... 13
6.4 NULL Y ENDP................................................................................................................................... 14
6.5 ZEROP, PLUSP, MINUSP, EVENP, ODDP, > Y <.......................................................................... 14
6.6 AND, OR Y NOT ............................................................................................................................... 14
6.7 IF, WHEN Y UNLESS....................................................................................................................... 15
6.8 COND ................................................................................................................................................ 15
6.9 CASE.................................................................................................................................................. 16
7. ABSTRACCIÓN DE PROCEDIMIENTOS Y RECURSIÓN .............................................................. 17
7.1 PROCEDIMIENTOS RECURSIVOS ............................................................................................... 17
7.2 PARÁMETROS OPCIONALES ....................................................................................................... 20
7.3 PARÁMETROS RESTANTES ......................................................................................................... 20
7.4 PARÁMETROS CLAVE................................................................................................................... 21
7.5 PARÁMETROS AUXILIARES........................................................................................................ 21
8. TRANSFORMACIONES Y FUNCIONES ANÓNIMAS...................................................................... 22
i
PROGRAMACIÓN EN LISP SISTEMAS DE INTELIGENCIA ARTIFICIAL
8.1 MAPCAR ...........................................................................................................................................22
8.2 REMOVE-IF Y REMOVE-IF-NOT...................................................................................................22
8.3 COUNT-IF Y FIND-IF .......................................................................................................................22
8.4 FUNCALL Y APPLY.........................................................................................................................23
8.5 FUNCIONES ANÓNIMAS (LAMBDA) ..........................................................................................23
9. ITERACIÓN ..............................................................................................................................................24
9.1 DOTIMES ..........................................................................................................................................24
9.2 DOLIST..............................................................................................................................................24
9.3 DO Y DO* ..........................................................................................................................................25
9.4 LOOP..................................................................................................................................................25
9.5 PROG1 Y PROGN..............................................................................................................................26
10. LECTURA Y ESCRITURA.................................................................................................................26
10.1 PRINT, PRIN1, PRINC Y TERPRI....................................................................................................26
10.2 READ .................................................................................................................................................27
10.3 FORMAT ...........................................................................................................................................27
10.4 WITH-OPEN-FILE............................................................................................................................28
10.5 ELT.....................................................................................................................................................29
10.6 STRING= Y STRING-EQUAL..........................................................................................................29
10.7 CHAR= Y CHAR-EQUAL.................................................................................................................29
10.8 SEARCH ............................................................................................................................................30
10.9 READ-CHAR.....................................................................................................................................30
10.10 READ-LINE.......................................................................................................................................30
11. BIBLIOGRAFÍA...................................................................................................................................31
ii
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
PROGRAMACIÓN EN LISP
1. INTRODUCCIÓN
La manipulación simbólica es el bloque constructivo básico de los programas de inteligencia
artificial. Programas para manipulación simbólica pueden reconocer expresiones simbólicas
particulares y pueden dividir expresiones para construir nuevas.
LISP es un lenguaje diseñado para manipulación simbólica, en contraste con los lenguajes de
programación convencionales que están primordialmente diseñados para procesamiento
numérico. En lugar de manipular estructuras de datos numéricos (como números y arreglos),
los programas en LISP típicamente manipulan estructuras de datos simbólicos (como palabras
y oraciones).
Lo que distingue a LISP de otros lenguajes de programación, es que está diseñado para
evolucionar. Ofrece construcciones especiales que permite escribir programas que escriben
programas.
A continuación se presenta una colección de lecciones diseñadas para aprender los
fundamentos de programación utilizando Common LISP. Este es un poderoso lenguaje de
inteligencia artificial rico en construcciones y funciones para operar sobre estructuras de datos
creados por el usuario. Sin embargo, existe un pequeño subconjunto del Common LISP, que
se puede utilizar para ilustrar muchos de los conceptos fundamentales de programación,
requeridos para comprender el lenguaje LISP.
2. TIPOS DE DATOS
En LISP, virtualmente cualquier estructura de datos puede ser representada como un objeto.
LISP utiliza dos tipos de objetos: átomos y listas.
Los átomos son objetos simples que pueden ser simbólicos o numéricos. Los átomos
numéricos o simplemente números, pueden ser enteros, racionales, reales y complejos, tanto
positivos como negativos. Por ejemplo:
12 2.5 -30 0.005 -8.0 1997 2/3 #C(0 2) -5/8
Los átomos simbólicos o simplemente símbolos, pueden incluir palabras, letras y caracteres
especiales. Por ejemplo:
Hola P200 Esto_es_un_átomo + - / *
Una lista es un objeto compuesto que consiste de cero o más átomos o listas encerradas entre
paréntesis. Por ejemplo:
() (9) (Politécnica Nacional) (+ 12 76) (colores (rojo azul verde))
A los átomos y listas se los denomina expresiones simbólicas o simplemente expresiones.
Estas expresiones constituyen los tipos de datos. En LISP, los valores son los que tienen
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 1
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
tipos, no las variables. No es necesario declarar los tipos de variables porque todas las
variables pueden contener objetos de cualquier tipo.
Las ocurrencias específicas de los diversos tipos de datos se denominan objetos. Así, 1997 es
un objeto que pertenece al tipo de datos número, HOLA es un objeto del tipo de datos símbolo
y (A B C) es un objeto del tipo de datos lista.
LISP tiene también muchos otros tipos de datos, incluyendo caracteres, arreglos, cadenas y
estructuras.
La estructura básica, de mayor importancia en LISP, es la lista. Una lista puede utilizarse
para representar una estructura de árbol. Por ejemplo la siguiente lista representa la
descripción del árbol de la Figura 1.
( X ( A ) ( B ( E ) ( F ) ( G ) ) ( C ) ( D ) )
Figura. 1. Representación en árbol
E F G
DCA B
X
Las listas también se emplean en procedimientos y funciones. A LISP se lo puede considerar
como un lenguaje de programación funcional porque utiliza funciones para manipular las
estructuras de expresiones simbólicas.
3. INTERACCIÓN CON EL INTÉRPRETE LISP
La interacción con LISP es muy similar a la que se realiza cuando se emplea una calculadora
de bolsillo. En primer lugar, ante el símbolo del interprete (>) se ingresa una expresión, luego
LISP lee la expresión, la evalúa y entrega el resultado. Para prevenir la evaluación de una
expresión, se debe poner antes de la expresión el apóstrofe ( ' ).
Si se ingresa el nombre de un símbolo sin el apóstrofe, el sistema retorna el valor asociado al
símbolo si está definido, caso contrario despliega un mensaje de error. Por ejemplo:
> HOLA
;; Error: Unbound variable HOLA in #<function 1 #x811040>
;; Returning to Top Level
> 'HOLA
HOLA
>
2 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
Por convención, ciertos átomos se evalúan a sí mismos. Entre los átomos simbólicos, T
(VERDADERO) y NIL (NULO) siempre se auto evalúan. También los átomos numéricos se
evalúan a sí mismos:
> t
T
> nil
NIL
> 34
34
> 19.45
19.45
>
Las listas se ingresan encerrando sus elementos entre paréntesis. No importa lo que esté en la
lista, LISP trata de evaluarla asumiendo que el primer elemento es el nombre de una función o
de un procedimiento y que los otros elementos son sus argumentos. Dado un conjunto
ordenado de objetos, una función LISP retorna un valor único, basado en sus argumentos.
Pero si se antepone a la lista el apóstrofe, el sistema responde con la misma lista. Por
ejemplo:
> (A)
;; Error: Call to undefined function A in #<function 0 #xE72950>
;; Returning to Top Level
> '(A)
(A)
> (A B)
;; Error: Unbound variable B in #<function 0 #xE7B944>
;; Returning to Top Level
> '(A B)
(A B)
Existen dos tipos de funciones en LISP, las definidas por el sistema y las definidas por el
usuario. Las funciones definidas por el sistema se las denomina también funciones primitivas.
Escribir programas en LISP consiste en utilizar las funciones primitivas y definir funciones
adicionales para realizar alguna tarea deseada.
4. PRINCIPALES FUNCIONES PRIMITIVAS
LISP es un acrónimo de LISt Processing. Como es de esperar, LISP proporciona funciones
primitivas para operar sobre listas de objetos. En LISP, las llamadas a funciones utilizan el
siguiente formato:
(nombre arg1 arg2 … argN)
Donde nombre corresponde al nombre de la función, arg1 es el primer argumento, arg2 es el
segundo argumento, y así sucesivamente.
Al proceso de reservar un lugar en la memoria del computador con el fin de almacenar un
valor para un símbolo se lo denomina ligadura; y al proceso de almacenar un valor en ese
lugar asignación. El proceso de recuperar un valor de ese lugar es un tipo de evaluación.
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 3
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
4.1 SETF
LISP asocia símbolos conforme los encuentra. Una manera de asignar un valor a un símbolo
es mediante la función primitiva SETF. Esta función hace que el valor de su segundo
argumento se asigne a su primer argumento.
> (SETF AÑO '1997)
1997
> AÑO
1997
> (SETF animales '(perro gato león tigre))
(PERRO GATO LEóN TIGRE)
> animales
(PERRO GATO LEóN TIGRE)
Se pueden incluir varios pares símbolo - valor en una sola instrucción SETF. Los argumentos
que están en posición impar no se evalúan, sólo los que están en lugares pares. La función
devuelve el valor del argumento final.
> (SETF FELINOS '(GATO LEÓN TIGRE)
ROEDORES '(RATÓN CONEJO CUY))
(RATÓN CONEJO CUY)
> FELINOS
(GATO LEÓN TIGRE)
> ROEDORES
(RATÓN CONEJO CUY)
Una de las operaciones más comunes es la extracción o selección de uno de los miembros de
una lista. Las funciones que realizan esta operación de denominan funciones selectoras. Las
principales funciones selectoras son: FIRST y REST. Los nombres dados a estas funciones
en implementaciones antiguas son: CAR y CDR respectivamente.
4.2 FIRST (CAR)
Devuelve el primer objeto de una lista dada como argumento.
> (FIRST '(amarillo azul rojo))
AMARILLO
4.3 REST (CDR)
Hace el trabajo complementario a FIRST. Devuelve una lista que contiene todos los objetos
de la lista original, excepto el primero.
> (REST '(amarillo azul rojo))
(AZUL ROJO)
4.4 NTHCDR
Elimina los n primeros elementos (primer argumento), de una lista dada como segundo
argumento. Si el primer argumento de NTHCDR es mayor o igual que el número de
elementos de la lista, retorna NIL.
> (NTHCDR 2 '(amarillo azul rojo))
(ROJO)
> (NTHCDR 3 '(amarillo azul rojo))
NIL
4 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
4.5 BUTLAST
Es similar a NTHCDR, sólo que en lugar de eliminar los primeros n elementos, elimina los n
últimos. También difiere en el orden de los argumentos, la lista es el primer argumento y el
valor de n es el segundo. Si no existe el segundo argumento, sólo se elimina el último
elemento.
> (BUTLAST '(amarillo azul rojo) 2)
(AMARILLO)
> (BUTLAST '(amarillo azul rojo))
(AMARILLO AZUL)
4.6 LAST
Devuelve una lista en la que se ha eliminado todos los elementos, excepto el último.
> (LAST '(amarillo azul rojo))
(ROJO)
Es importante notar que LAST devuelve una lista conteniendo al último elemento de la lista
original. Para extraer el último elemento de la lista, se debe combinar FIRST y LAST:
> (FIRST (LAST '(amarillo azul rojo)))
ROJO
El anterior ejemplo ilustra la posibilidad de utilizar el valor retornado por la llamada a una
función como argumento para otra función.
4.7 LENGTH y REVERSE
La primitiva LENGTH cuenta el número de elementos del nivel superior que hay en una lista,
y REVERSE invierte el orden de estos. Ambas funciones consideran que su argumento es
una lista de elementos, sin importar que estos sean listas o átomos. Cuando sus argumentos
son listas cuyos objetos son listas, no se afectan a las sublistas.
> (LENGTH '(amarillo azul rojo))
3
> (LENGTH '((Pichincha Quito) (Azuay Cuenca) (Carchi Tulcán)))
3
> (REVERSE '(amarillo azul rojo))
(ROJO AZUL AMARILLO)
> (REVERSE '((Pichincha Quito) (Azuay Cuenca) (Carchi Tulcán)))
((CARCHI TULCáN) (AZUAY CUENCA) (PICHINCHA QUITO))
LISP también proporciona funciones constructoras. Estas son: CONS, APPEND y LIST.
4.8 CONS
Toma sólo 2 argumentos: una expresión y una lista. Retorna una nueva lista, donde el primer
elemento es la expresión y los restantes son los de la lista dada como segundo argumento.
> (CONS 'perro '(gato loro ratón))
(PERRO GATO LORO RATóN)
> (CONS '(A B) '(X Y))
((A B) X Y)
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 5
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
4.9 APPEND
Acepta una o más listas como argumentos. Retorna una lista en la que están combinados los
elementos del nivel superior de las listas dadas como argumentos.
> (APPEND '(perro) '(gato loro ratón))
(PERRO GATO LORO RATóN)
> (APPEND '(A B) '(X Y))
(A B X Y)
> (APPEND '(a) '(b c) '(w (x y) z))
(A B C W (X Y) Z)
>
4.10 LIST
Trabaja con uno o más argumentos. Su resultado es una nueva lista en la que cada uno de los
argumentos se vuelve un elemento.
> (LIST 'perro '(gato loro ratón))
(PERRO (GATO LORO RATóN))
> (LIST '(perro) '(gato loro ratón))
((PERRO) (GATO LORO RATóN))
> (LIST 'perro 'gato 'loro 'ratón)
(PERRO GATO LORO RATóN)
4.11 REMOVE
Acepta dos argumentos: un símbolo y una lista. Retorna la lista dada como segundo
argumento, en la que todas las ocurrencias en el nivel superior del símbolo dado como primer
argumento ha sido removido.
> (REMOVE 'd '(a (b c) d e f))
(A (B C) E F)
> (REMOVE '(b c) '(a (b c) d e f))
(A (B C) D E F)
> (REMOVE 'b '(a (b c) d e f))
(A (B C) D E F)
>
Es importante notar que las funciones CONS, APPEND, LIST y REMOVE no alteran el valor
de los objetos utilizados como sus argumentos.
4.12 ASSOC
Para acceder a sublistas, LISP proporciona la función ASSOC. Esta primitiva está
especialmente diseñada para trabajar con listas de asociación. Una lista de asociación consta
de una serie de sublistas. El primer elemento de cada sublista se utiliza como clave para
recuperar la sublista completa.
(ASSOC <clave> <lista de asociación>)
La operación de esta primitiva se muestra en los siguientes ejemplos:
> (SETF PC1 '((RAM 8KB) (DISCO 1.2GB))
PC2 '((RAM 32KB) (DISCO 2.0 GB)))
((RAM 32KB) (DISCO 2.0 GB))
6 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
> (ASSOC 'RAM PC1)
(RAM 8KB)
> (ASSOC 'DISCO PC2)
(DISCO 2.0 GB)
ASSOC siempre retorna la sublista completa cuyo primer elemento es igual a la clave. En el
caso de que más de una sublista cumpla con la condición, sólo devuelve la primera
ocurrencia, el resto de sublistas permanecen ocultas.
LISP también proporciona primitivas para operar sobre números enteros, racionales, reales y
complejos: +, -, *, /, FLOAT, ROUND, MAX, MIN, EXPT, SQRT, ABS.
4.13 SUMA, RESTA, PRODUCTO y DIVISIÓN
Las funciones suma ( + ), resta ( - ), producto (*) y división ( / ), pueden operar con uno o
más argumentos.
> (+ 1.5 5 3.9 12)
22.4
> (- 16 4.5)
11.5
> (* 2 3 4)
24
> (+ #C(0 2) #C(1 -3))
#C(1 -1)
Cuando sus 2 argumentos son números enteros y no se dividen exactamente, la división
retorna un número racional. Basta con que uno de sus argumentos sea un número real, la
división dará como resultado también un número real.
> (/ 3 4)
3/4
> (/ 3.0 4)
0.75
> (/ #C(3 4) #C(1 -1))
#C(-1/2 7/2)
> (/ #C(3.0 4.0) #C(1.0 -1.0))
#C(-0.5 3.5)
Si la función divisora sólo tiene un argumento, calcula el recíproco del número dado:
> (/ 3)
> 1/3
> (/ #C(-4 3))
#C(-4/25 -3/25)
> (/ #C(-4.0 3.0))
#C(-0.16 -0.12)
4.14 FLOAT
Cuando se desea obtener un resultado de punto flotante, se puede utilizar FLOAT, una
primitiva que convierte su argumento en número real.
> (FLOAT (/ 3 4))
0.75
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 7
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
4.15 ROUND
Redondea el resultado de la división hacia el entero más cercano. ROUND entrega dos
valores. El primero es el entero más cercano. Si el resulado está justo en el medio de dos
valores enteros, retorna el numero par. El segundo valor es el residuo producido por la
operación de redondeo.
> (ROUND 0.99)
1
-0.01
> (ROUND -1.5)
-2
0.5
> (ROUND 3 2)
2
-1
4.16 TRUNCATE
Trunca el resultado de la división de sus argumentos, en dirección al entero más cercano al
cero. Retorna dos valores: el entero con el mismo signo que el resultado de la división y el
residuo producido por la operación de truncado.
> (TRUNCATE 0.99)
0
0.99
> (TRUNCATE -1.5)
-1
-0.5
> (TRUNCATE 3 2)
1
1
>
4.17 REM
Toma dos argumentos y retorna el residuo de la división entre ellos.
> (REM 17 6)
5
> (REM -17 6)
-5
> (REM -17 -6)
-5
> (REM 17 -6)
5
>
4.18 MAX y MIN
Las primitivas MAX y MIN, retornan el máximo y el mínimo, respectivamente, dada una
secuencia de números:
> (MAX 2 5 3)
5
> (MIN 2 5 3)
2
8 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
4.19 EXPT
Calcula potencias elevando su primer argumento al segundo. Puede operar sobre números
enteros y reales.
> (EXPT 3 4)
81
> (EXPT 2.3 4.2)
33.0565032282171
4.20 SQRT
SQRT extrae la raíz cuadrada de su argumento. Si el argumento es un número negativo,
retorna un número complejo:
> (SQRT 27)
5.19615242270663
> (SQRT -25)
#C(0.0 5.0)
4.21 ABS
Retorna el valor absoluto de su argumento:
> (ABS -34)
34
5. DEFINICIÓN DE PROCEDIMIENTOS Y LIGADURA
Una de las principales fortalezas de LISP es que los programas pueden ser usados como datos
para otros programas. Esto se deriva del hecho de que los datos y los programas en LISP son
representados de la misma forma.
Los programas son construidos en base a formas y funciones. Las formas son las unidades
fundamentales de los programas en LISP, los cuales son evaluados para retornar uno o más
valores y también pueden producir otros efectos colaterales. Algunas pueden llamar a
funciones. A su vez, una función es una colección de formas que son evaluadas cuando se
llama a la función. Las funciones son llamadas con sus respectivos argumentos. A las
funciones se las puede dar nombres utilizando símbolos.
Para definir una función o procedimiento, LISP necesita conocer 3 cosas:
• El nombre de la función o procedimiento.
• Los de argumentos que necesita.
• La tarea que la función o procedimiento debe realizar
A los argumentos de la función o procedimiento se los denomina parámetros. Los
parámetros de un procedimiento son variables ligadas a él. Una variable es un símbolo con
el que se designa algún lugar de memoria destinado para almacenar un valor. Al iniciar la
ejecución de la función, a cada parámetro se le asigna un valor. La tarea definida para ser
realizada, constituye el cuerpo del procedimiento. El cuerpo de un procedimiento consta de
las formas que son evaluadas cuando éste se utiliza.
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 9
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
Para definir procedimientos LISP proporciona la primitiva DEFUN, un acrónimo de DEFinir
FUNción. Para documentar las construcciones, LISP permite la inserción de comentarios. El
punto y coma (;) indica al interprete que todo lo que está a la derecha hasta el fin de la línea,
es comentario.
5.1 DEFUN
La plantilla general para DEFUN es la siguiente:
(DEFUN < nombre del procedimiento> ; nombre de la función
( < parámetro 1> <parámetro 2> … <parámetro N) ; argumentos
< forma 1 > ; cuerpo de la función:
< forma 2 > ; varias formas.
…
< forma M > )
Como ejemplos, a continuación se definen un procedimiento para rotar a la izquierda y otro
para rotar a la derecha los elementos de una lista dada como argumento:
> (DEFUN rotizq (Lista)
(APPEND (REST Lista) (LIST (FIRST Lista))))
ROTIZQ
> (rotizq '(a b c d e))
(B C D E A)
> (DEFUN rotder (Lista)
(APPEND (LAST Lista) (BUTLAST Lista)))
ROTDER
> (rotder '(a b c d e))
(E A B C D)
5.2 LET
Es una primitiva que liga parámetros de la misma manera que éstos son ligados al iniciar la
ejecución de un procedimiento. La plantilla general de LET es la siguiente:
( LET ( (< parámetro 1> <valor inicial 1 )
…
( parámetro N> <valor inicial N ) )
< forma 1>
…
< forma M> )
A continuación, utilizando LET, se construye una operación que retorna una lista que tiene
los objetos extremos de la lista original dada.
> (SETF semana '(LUN MAR MIE JUE VIE SAB DOM))
(LUN MAR MIE JUE VIE SAB DOM)
> (LET ((primero (FIRST semana))
(último (LAST semana)))
(CONS primero último))
(LUN DOM)
10 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
Como se demuestra en el siguiente ejemplo, la primitiva LET evalúa en paralelo sus formas
para valores iniciales, antes de que cualquiera de sus parámetros sea ligado.
> (SETF a 'Valor-Externo) ; El valor de a es Valor-Externo
VALOR-EXTERNO
> (LET ((a 'Valor-Interno) ; El valor de a será Valor-Interno
(b a)) ; El valor de b será Valor-Externo
(LIST a b))
(VALOR-INTERNO VALOR-EXTERNO)
>
5.3 LET*
LET* es la versión de LET que evalúa en forma secuencial sus formas para valores iniciales.
Esto es, liga los parámetros de tal forma que el valor de un parámetro ligado con anterioridad
puede ser utilizado para calcular el valor de un parámetro ligado después.
> (SETF a 'Valor-Externo) ; El valor de a es Valor-Externo
VALOR-EXTERNO
> (LET* ((a 'Valor-Interno) ; El valor de a será Valor-Interno
(b a)) ; El valor de b será Valor-Interno
(LIST a b))
(VALOR-INTERNO VALOR-INTERNO)
6. PREDICADOS Y CONDICIONALES
Un predicado es un procedimiento que devuelve un valor que puede ser verdadero o falso. El
resultado falso siempre se indica con NIL, mientras que el símbolo T o cualquier valor
diferente de NIL se considera como verdadero. Estas pruebas, combinadas con condicionales
permiten definir procedimientos mucho más poderosos.
6.1 =, EQ, EQL y EQUAL
Existen varios predicados que determinan si sus argumentos son iguales.
• El predicado = verifica que sus argumentos representen el mismo número, aun cuando no
sean del mismo tipo numérico.
• EQ verifica que sus argumentos estén representados en las misma localidades de memoria,
es decir que sean símbolos idénticos.
• EQL primero verifica si sus argumentos satisfacen EQ. Si no lo hacen trata de ver si son
números del mismo tipo y con igual valor.
• EQUAL primero verifica si sus argumentos satisfacen EQL. Si no lo hacen trata de
verificar si son listas cuyos elementos satisfacen EQUAL.
> (SETF X 4 Y 4.0 FELINO 'GATO AVE 'PATO DIAS '(LUN MAR MIE JUE VIE))
(LUN MAR MIE JUE VIE)
> (= X Y)
T
> (EQ X Y)
NIL
> (EQ FELINO 'GATO)
T
> (EQ '(LUN MAR MIE JUE VIE) DIAS)
NIL
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 11
> (EQL AVE 'PATO)
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
T
> (EQL '(LUN MAR MIE JUE VIE) DIAS)
NIL
> (EQUAL 'GATO FELINO)
T
> (EQUAL '(LUN MAR MIE JUE VIE) DIAS)
T
> (EQUAL X Y)
NIL
6.2 MEMBER
El predicado MEMBER verifica que su primer argumento sea un elemento del nivel superior
de su segundo argumento, que debe ser una lista. Devuelve lo que queda de la lista al
encontrar el símbolo coincidente, si éste pertenece a dicha lista.
> (SETF ORACION '(La imaginación es más importante que el conocimiento)
PAREJAS '((Luis Ana) (Rodrigo Martha) (Juan Rosa)))
((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA))
> (MEMBER 'importante ORACION)
(IMPORTANTE QUE EL CONOCIMIENTO)
> (MEMBER 'Rodrigo PAREJAS)
NIL
> (MEMBER '(Rodrigo Martha) PAREJAS)
NIL
MEMBER normalmente hace sus pruebas utilizando EQL, por este motivo, en el ejemplo
anterior, no puede reconocer a la sublista (Rodrigo Martha) como miembro de PAREJAS.
Pero COMMON LISP permite el uso de argumentos clave para modificar el comportamiento
de ciertos procedimientos como MEMBER. La sintaxis para incluir argumentos clave en el
predicado MEMBER, requiere de una palabra clave :TEST o :TEST-NOT, seguida por el
argumento clave. El argumento clave está compuesto por los caracteres #’ y el nombre del
procedimiento a ser utilizado, en este caso resultaría #’EQUAL.
En particular, la palabra clave :TEST indica que el siguiente argumento especifica la prueba
que debe usar MEMBER. Si en su lugar aparece la palabra clave :TEST-NOT, MEMBER
devuelve lo que queda de la lista luego de la primera aparición de un elemento, si lo hay, que
no sea igual al primer argumento, donde el argumento clave determina qué es lo que significa
igual.
El objetivo de los caracteres #’ es producir un procedimiento objeto a partir del nombre del
procedimiento. Los cinco caracteres EQUAL constituyen el nombre del procedimiento. Las
instrucciones de la computadora que ejecutan la prueba requerida constituyen el
procedimiento objeto. De esta forma, el argumento clave resulta ser una variable cuyo valor
es un procedimiento objeto, y como tal puede ser ligada a un símbolo.
> (MEMBER 'Rodrigo PAREJAS :TEST #'EQUAL)
NIL
> (MEMBER 'Rodrigo PAREJAS :TEST-NOT #'EQUAL)
((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA))
> (SETF PRED #'EQUAL) ; Argumento clave es ligado a símbolo PRED
#<function 2 #x8D2ADC> ; Respuesta del sistema
> (MEMBER '(Rodrigo Martha) PAREJAS :TEST PRED)
((RODRIGO MARTHA) (JUAN ROSA))
12 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
> (MEMBER '(Rodrigo Martha) PAREJAS :TEST-NOT PRED)
((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA))
> (MEMBER '(Luis Ana) PAREJAS :TEST PRED)
((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA))
> (MEMBER '(Luis Ana) PAREJAS :TEST-NOT PRED)
((RODRIGO MARTHA) (JUAN ROSA))
> (MEMBER '(Juan Rosa) PAREJAS :TEST PRED)
((JUAN ROSA))
> (MEMBER '(Juan Rosa) PAREJAS :TEST-NOT PRED)
((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA))
En programas antiguos, se pueden ver expresiones como (FUNCTION EQUAL), en lugar de
#’EQUAL. La combinación #’ es un tipo de refinamiento sintáctico. En realidad, el intérprete
LISP al encontrar la secuencia #’<expresión> la convierte en (FUNCTION <expresión>).
Algunas versiones modernas de LISP todavía soportan la sintaxis antigua, por compatibilidad.
> (MEMBER '(Rodrigo Martha) PAREJAS :TEST (FUNCTION EQUAL))
((RODRIGO MARTHA) (JUAN ROSA))
>
6.3 ATOM, NUMBERP, SYMBOLP y LISTP
LISP tiene varios predicados que verifican si un objeto pertenece a un tipo especial de datos.
PREDICADO PRUEBA
ATOM ¿Es un átomo?
NUMBERP ¿Es un número?
SYMBOLP ¿Es un símbolo?
LISTP ¿Es una lista?
> PI
3.14159265358979
> (ATOM PI)
T
> (NUMBERP PI)
T
> (SYMBOLP PI)
NIL
> (SYMBOLP 'PI)
T
> (LISTP PI)
NIL
> (LISTP 'PI)
NIL
En LISP existe una importante peculiaridad ya NIL y la lista vacía ( ) son totalmente
equivalentes. Además, NIL y ( ) son tanto símbolos como listas.
> NIL
NIL
> ()
NIL
> (ATOM NIL)
T
> (ATOM ())
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 13
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
T
> (SYMBOLP NIL)
T
> (SYMBOLP ())
T
> (LISTP NIL)
T
> (LISTP ())
T
6.4 NULL y ENDP
Son predicados que verifican si su argumento es una lista vacía. Los siguientes ejemplos
ilustran la diferencia entre los dos predicados.
> (REST (LAST '(A B C D)))
NIL
> (NULL (REST (LAST '(A B C D))))
T
> (ENDP (REST (LAST '(A B C D))))
T
> (NULL PI)
NIL
> (ENDP PI)
T
> (NULL 'PI)
NIL
> (ENDP 'PI)
T
6.5 ZEROP, PLUSP, MINUSP, EVENP, ODDP, > y <
Además de NUMBERP, los predicados que trabajan con átomos numéricos, son los
siguientes:
PREDICADO PRUEBA
ZEROP ¿Es cero?
PLUSP ¿Es positivo?
MINUSP ¿Es negativo?
EVENP ¿Es número par?
ODDP ¿Es número impar?
> ¿Están en orden descendente?
< ¿Están en orden ascendente?
6.6 AND, OR y NOT
Para combinar los resultados de las pruebas de dos o más predicados, se pueden utilizar los
operadores lógicos AND, OR y NOT.
14 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
OPERADOR OPERACIÓN
AND • Los argumentos son evaluados de izquierda a derecha. Si alguno de ellos tiene
como valor NIL, el resto de los argumentos ya no se evalúan y el valor devuelto es
NIL.
• Si todos los argumentos tienen un valor diferente de NIL, se devuelve el valor del
último de los argumentos.
OR • Los argumentos son evaluados de izquierda a derecha. Si alguno de ellos tiene
valor diferente de NIL, ninguno de los argumentos se evalúan y el valor devuelto
es ese valor diferente de NIL.
• Si ninguno de los argumentos tiene un valor diferente de NIL, se devuelve el valor
NIL.
NOT • Convierte valores NIL a T y valores diferentes de NIL a NIL.
> (SETF mascotas '(perro gato))
(PERRO GATO)
> (AND (MEMBER 'perro mascotas) (MEMBER 'tigre mascotas))
NIL
> (OR (MEMBER 'perro mascotas) (MEMBER 'tigre mascotas))
(PERRO GATO)
> (AND (MEMBER 'perro mascotas) (NOT (MEMBER 'tigre mascotas)))
T
> (OR (MEMBER 'perro mascotas) (NOT (MEMBER 'tigre mascotas)))
(PERRO GATO)
> (OR (NOT (MEMBER 'perro mascotas)) (MEMBER 'tigre mascotas))
NIL
6.7 IF, WHEN y UNLESS
Los predicados se utilizan casi siempre dentro de condicionales, para determinar de entre
varias formas cuál debe evaluarse. LISP proporciona los siguientes condicionales básicos:
(IF <prueba> <forma a evaluar si la prueba es no NIL> <forma a evaluar si la prueba es NIL>)
(WHEN <prueba> <forma(s) a evaluar si la prueba es no NIL>)
(UNLESS <prueba> <forma(s) a evaluar si la prueba es NIL>)
Tanto WHEN como UNLESS, pueden tener cualquier número de argumentos. El primero
siempre es la forma de prueba; el último proporciona el valor que se devolverá. Sus
argumentos, después del primero, sólo se evalúan si el valor de la prueba así lo indica.
6.8 COND
Es un condicional mucho más versátil que IF, WHEN y UNLESS. La plantilla de esta forma
es la siguiente:
(COND
(<prueba 1> <consecuente 1-1> <consecuente 1-2> … <consecuente 1-N>)
(<prueba 2> <consecuente 2-1> <consecuente 2-2> … <consecuente 2-N>)
…
(<prueba M> <consecuente M-1> <consecuente M-2> … <consecuente M-N>))
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 15
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
Cada cláusula contiene una prueba y cero o más formas adicionales denominadas
consecuentes. Se evalúan en secuencia las formas de prueba de cada cláusula hasta que se
encuentre una cuyo valor sea diferente de NIL. En este caso se dice que la cláusula
correspondiente se activa y se evalúan sus formas consecuentes. El valor que retorna COND,
es el de la última forma consecuente de la cláusula activada. Si el valor de todas las formas
de prueba es NIL, el valor que retorna COND, también es NIL. Si una cláusula con una
forma de prueba diferente de NIL no tiene formas consecuentes, entonces el valor retornado
por COND es el valor de la forma de prueba.
> (DEFUN sol-ecuación-cuad (a b c)
(SETF delta (- (* b b) (* 4 a c)))
(COND
((PLUSP delta)
(LET ((f1 (- (/ b (* 2 a)))) (f2 (/ (SQRT delta) (* 2 a)))) (LIST 'X1 '= (+ f1 f2) 'X2 '= (- f1 f2))))
((MINUSP delta) (LIST 'No 'hay 'solución 'real!))
(T (LIST 'X1 '= 'X2 '= (- (/ b (* 2 a)))))))
SOL-ECUACIóN-CUAD
> (sol-ecuación-cuad 1 -1 20)
(NO HAY SOLUCIóN REAL!)
> (sol-ecuación-cuad 1 -1 -20)
(X1 = 5.0 X2 = -4.0)
> (sol-ecuación-cuad 1 -10 25)
(X1 = X2 = 5)
6.9 CASE
CASE evalúa la forma clave y la compara con todas las claves sin evaluar, usando EQL. Si la
clave se encuentra, la cláusula correspondiente se activa y todas las formas consecuentes se
evalúan. Su plantilla es la siguiente:
(CASE <forma clave>
(<clave 1> <consecuente 1-1> <consecuente 1-2> … <consecuente 1-N>)
(<clave 2> <consecuente 2-1> <consecuente 2-2> … <consecuente 2-N>)
(<clave M> <consecuente M-1> <consecuente M-2> … <consecuente M-N>))
• Si ninguna de las cláusulas se activa, CASE retorna NIL.
• Si la clave en la última cláusula es T u OTHERWISE, y ninguna de las otras cláusulas se
activa, se activa la última.
• Si la clave es una lista en lugar de un átomo, CASE evalúa la forma clave y usa MEMBER
para buscarla en la lista de claves sin evaluar. Si la clave se encuentra, la cláusula
correspondiente se activa y todas las formas consecuentes se evalúan.
> (DEFUN área (figura radio)
(CASE figura
(círculo (* pi radio radio))
(esfera (* 4 pi radio radio))
(OTHERWISE 'No-es-círculo-o-esfera)))
áREA
> (área 'círculo 3)
28.2743338823081
> (área 'esfera 4)
201.061929829747
> (área 'triángulo 5)
NO-ES-CíRCULO-O-ESFERA
16 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
7. ABSTRACCIÓN DE PROCEDIMIENTOS Y RECURSIÓN
La abstracción de procedimientos es un proceso que ayuda a construir programas grandes y
complicados sobre la base de una combinación de funciones o procedimientos más simples.
La abstracción de procedimientos ayuda a pensar en un nivel superior, al permitir obviar los
detalles de cómo se hacen las cosas en un nivel inferior. Se puede programar de arriba hacia
abajo, trabajando primero en los procedimientos de nivel superior, posponiendo los de nivel
inferior. La abstracción de procedimientos ayuda a mantener las definiciones breves y
comprensibles.
Un caso especial e importante de la abstracción de procedimientos es aquel en el cual la
abstracción sobre la que se construye un procedimiento es el mismo procedimiento.
7.1 PROCEDIMIENTOS RECURSIVOS
Cuando un procedimiento se llama a sí mismo, se dice que hace una llamada recursiva. A las
definiciones que describen un procedimiento parcialmente en términos de llamadas recursivas
se las denomina definiciones recursivas.
Suponiendo que no se tiene la función primitiva MEMBER, definamos como un
procedimiento recursivo sencillo la función MBR. Dado un átomo y una lista como
argumentos, se tiene la siguiente descripción para la función MBR:
1. Si la lista es nula, el átomo no es un miembro de la lista, retornar NIL.
2. Si el átomo es igual al primer elemento de la lista, entonces el átomo es miembro de la
lista, retornar T.
3. Si el átomo no es igual al primer elemento de la lista, entonces el átomo es miembro de la
lista si y sólo si es un miembro del resto de la lista.
Las dos primeras consideraciones son relativamente sencillas de entender. La tercera es un
poco más sutil y puede ser interpretada como una llamada recursiva a MBR, dándole como
argumentos el átomo y el resto de la lista original.
Esto, traducido a LISP, resulta:
> (DEFUN MBR (átomo lista)
(COND
((ENDP lista) NIL)
((EQL átomo (FIRST lista)) T)
(T (MBR átomo (REST lista)))))
MBR
> (MBR 'a '(a b c d))
T
> (MBR 'b '(a b c d))
T
> (MBR 'd '(a b c d))
T
> (MBR 'b '())
NIL
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 17
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
Utilizando similares técnicas, definamos ahora la función EQLIST que retorna T si las dos
listas de átomos dadas como argumentos son iguales. La descripción para esta función es
como sigue:
Definir EQLIST con argumentos lista1 y lista2:
• Si la lista1 es vacía, retornar el resultado de comprobar si lista2 es vacía.
• Si la lista2 es vacía, retornar NIL.
• Si el primer elemento de lista1 y el primer elemento de lista2 no son iguales, retornar NIL.
• Si no, realizar una llamada recursiva a EQLIST dando como arguentos el resto de lista1 y
el resto de lista2.
> (DEFUN EQLIST (lista1 lista2)
(COND
((ENDP lista1) (ENDP lista2))
((ENDP lista2) NIL)
((NOT (EQL (FIRST lista1) (FIRST lista2))) NIL)
(T (EQLIST (REST lista1) (REST lista2)))))
EQLIST
> (EQLIST () '(A B C))
NIL
> (EQLIST '(A B C) ())
NIL
> (EQLIST () ())
T
> (EQLIST '(A B C) '(A B C))
T
> (EQLIST '(A B C) '(B C A))
NIL
Ahora definamos una versión de la función llamada ELIMINAR, la misma que acepta dos
argumentos: un átomo y una lista. El resultado es una lista en la que la ocurrencia de átomo
ha sido eliminada de la lista original dada. La descripción es la siguiente:
Definir ELIMINAR con átomo y lista como argumentos:
1. Si la lista es vacía, retornar NIL
2. Si el átomo es igual al primer elemento de la lista, retornar el resto de la lista.
3. Si no, construir una lista con el primer elemento de la lista y lo que retorne la llamada
recursiva a ELIMINAR con los argumentos átomo y resto de la lista.
> (SETF animales '(oso perro gato toro perro loro oso))
(OSO PERRO GATO TORO PERRO LORO OSO)
> (DEFUN ELIMINAR (átomo lista)
(COND
((ENDP lista) NIL)
((EQL átomo (FIRST lista)) (REST lista))
((CONS (FIRST lista) (ELIMINAR átomo (REST lista))))))
ELIMINAR
> (ELIMINAR ‘perro animales)
(OSO GATO TORO PERRO LORO OSO)
> (ELIMINAR 'oso animales)
(PERRO GATO TORO PERRO LORO OSO)
18 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
Como se puede ver de los resultados, sólo la primera ocurrencia de átomo es eliminada de la
lista. Realizando una modificación al procedimiento anterior, se define la función
ELIMINAR-TODO, capaz de eliminar todas la ocurrencias de átomo en la lista:
Definir ELIMINAR-TODO con átomo y lista como argumentos:
1. Si la lista es vacía, retornar NIL
2. Si el átomo es igual al primer elemento de la lista, llamar recursivamente a ELIMINAR-
TODO dándole como argumentos el átomo y el resto de la lista.
3. Si no, construir una lista con el primer elemento de la lista y lo que retorne la llamada
recursiva a ELIMINAR-TODO con los argumentos átomo y resto de la lista.
> (DEFUN ELIMINAR-TODO (átomo lista)
(COND
((ENDP lista) NIL)
((EQL átomo (FIRST lista)) (ELIMINAR-TODO átomo (REST lista)))
((CONS (FIRST lista) (ELIMINAR-TODO átomo (REST lista))))))
ELIMINAR-TODO
> (ELIMINAR-TODO 'perro animales)
(OSO GATO TORO LORO OSO)
> (ELIMINAR-TODO 'oso animales)
(PERRO GATO TORO PERRO LORO)
Como se vio anteriormente, la función primitiva REVERSE invierte todos los elementos del
nivel superior de una lista dada como argumento. La siguiente función denominada
INVERTIR, es una generalización de REVERSE, ya que invierte todos los elementos de una
lista, sean estos átomos o listas.
> (DEFUN INVERTIR (lista)
(COND
((ENDP lista) NIL)
((LISTP (FIRST (LAST lista)))
(CONS (INVERTIR (FIRST (LAST lista))) (INVERTIR (BUTLAST lista))))
(T (CONS (FIRST (LAST lista)) (INVERTIR (BUTLAST lista))))))
INVERTIR
> (SETF lista1 '(a b c d e f))
(A B C D E F)
> (SETF lista2 '((a b) (c d) e (f g)))
((A B) (C D) E (F G))
> (REVERSE lista1)
(F E D C B A)
> (INVERTIR lista1)
(F E D C B A)
> (REVERSE lista2)
((F G) E (C D) (A B))
> (INVERTIR lista2)
((G F) E (D C) (B A))
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 19
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
7.2 PARÁMETROS OPCIONALES
Los procedimientos hasta ahora definidos, han requerido de un argumento por cada
parámetro. Pero LISP también permite definir procedimientos con parámetros opcionales,
indicados con &OPTIONAL, para los cuales puede haber o no argumentos correspondientes.
> (DEFUN raíz (x &optional n)
(IF n (expt x (/ 1 n)) (sqrt x)))
RAíZ
> (raíz 9) ; llamada a raíz con un argumento, n se liga a NIL y se usa SQRT.
3.0
> (raíz 27 3) : llamada a raíz con 2 argumentos, n se liga a 3 y se usa EXPT.
3.0
Todos los parámetros opcionales que no tengan argumento correspondiente, se ligan al valor
NIL por omisión. Pero también se puede especificar el valor por omisión al que se deben
ligar los parámetros opcionales.
> (DEFUN raíz (x &optional (n 2))
(expt x (/ 1 n)))
RAíZ
> (raíz 16) ; llamada a raíz con un argumento, n se liga a 2.
4.0
> (raíz 64 3) ; llamada a raíz con 2 argumentos, n se liga a 3.
4.0
Los parámetros opcionales casi siempre simplifican los programas, al reducir la necesidad de
procedimientos auxiliares.
> (DEFUN cuenta-elementos (lista &optional (resultado 0))
(IF (ENDP lista) resultado
(cuenta-elementos (REST lista) (+ 1 resultado))))
CUENTA-ELEMENTOS
> (cuenta-elementos '(La imaginación es más importante que el conocimiento))
8
La llamada a cuenta-elementos con un sólo argumento hace que el valor inicial de resultado sea
cero. Pero el mismo procedimiento es usado con dos argumentos en las llamadas recursivas.
En este caso el valor por omisión de resultado se ignora en favor del valor del argumento
proporcionado.
7.3 PARÁMETROS RESTANTES
Un parámetro restante, indicado por &REST se liga a una lista de todos los valores de los
argumentos que de otra manera no tendrían un parámetro correspondiente.
> (DEFUN potencia (x &REST exponentes)
(POTEXP x exponentes))
POTENCIA
> (DEFUN potexp (resultado exponentes)
(IF (ENDP exponentes) resultado
(potexp (EXPT resultado (FIRST exponentes)) (REST exponentes))))
POTEXP
> (potencia 3)
20 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
3
> (potencia 3 2)
9
> (potencia 3 2 4)
6561
7.4 PARÁMETROS CLAVE
Un parámetro clave se usa en situaciones en las que hay varios parámetros, muchos de los
cuales casi siempre se ligan a valores por omisión. En tales situaciones si se usaran
parámetros opcionales, sería muy difícil recordar el orden de ellos, con su respectivo valor
inicial. Cuando se define procedimientos con parámetros clave, estos se indican con &KEY.
> (DEFUN rota-lista-der (lista n-puestos)
(IF (ZEROP n-puestos) lista
(rota-lista-der (APPEND (LAST lista) (BUTLAST lista)) (- n-puestos 1))))
ROTA-LISTA-DER
> (DEFUN rota-lista-izq (lista n-puestos)
(IF (ZEROP n-puestos) lista
(rota-lista-izq (APPEND (REST lista) (LIST (FIRST lista))) (- n-puestos 1))))
ROTA-LISTA-IZQ
> (DEFUN rota-lista (lista &KEY dirección (lugares 1))
(IF (EQ dirección 'izquierda)
(rota-lista-izq lista lugares)
(rota-lista-der lista lugares)))
ROTA-LISTA
> (rota-lista '(a b c d e) :dirección 'izquierda :lugares 3)
(D E A B C)
> (rota-lista '(a b c d e) :dirección 'derecha :lugares 3)
(C D E A B)
En el procedimiento ROTA-LISTA definido anteriormente, dirección y lugares, aparecen como
parámetros clave. En la llamada a la función, las palabras clave :dirección y :lugares, indican
la presencia de argumentos que deben ser asignados a los parámetros dirección y lugares. Las
ligaduras son determinadas por las palabras clave, no por el orden de aparición en la llamada.
Esto se demuestra en los siguientes ejemplos.
> (rota-lista '(a b c d e) :lugares 4 :dirección 'izquierda)
(E A B C D)
> (rota-lista '(a b c d e) :lugares 2 :dirección 'derecha)
(D E A B C)
7.5 PARÁMETROS AUXILIARES
Un parámetro auxiliar, indicado por &AUX, no corresponde a ningún argumento. Los
parámetros auxiliares en realidad son formas LET* disfrazadas.
> (DEFUN extremos (lista &AUX (primero (FIRST lista)) (último (LAST lista)))
(CONS primero último))
EXTREMOS
> (extremos '(a b c d e))
(A E)
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 21
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
8. TRANSFORMACIONES Y FUNCIONES ANÓNIMAS
Los procedimientos recursivos, permiten transformar y filtrar. Cuando se transforma una
lista, la longitud de la lista transformada es la misma que la longitud de la lista original.
Cuando se filtra una lista la longitud de la lista de salida es menor, a menos que todos los
elementos de la lista original pasen la prueba del filtro.
8.1 MAPCAR
Es una primitiva que facilita el procedimiento de transformación de listas. MAPCAR
requiere del nombre de un procedimiento de transformación junto con la lista de los
elementos que serán transformados. En el siguiente ejemplo MAPCAR se utiliza para
comprobar los números que son impares, utilizando la primitiva ODDP. La secuencia #’, tal
como se explico anteriormente, produce un procedimiento objeto, a partir de un nombre de
procedimiento. Cuando se evalúa una forma MAPCAR, LISP suministra cada elemento de su
segundo argumento al procedimiento de transformación especificado por su primer
argumento. El valor devuelto es una lista de resultados.
> (mapcar #'oddp '(1 2 3))
(T NIL T)
El procedimiento usado por MAPCAR no está restringido a ser un procedimiento de un
parámetro; si el procedimiento tiene más de un parámetro debe haber un número
correspondiente de listas de las cuales extraer argumentos. En el siguiente ejemplo
MAPCAR toma un elemento de cada lista de argumentos y los ensambla para un
procedimiento de transformación.
> (mapcar #'= '(1 2 3) '(3 2 1))
(NIL T NIL)
8.2 REMOVE-IF y REMOVE-IF-NOT
Son primitivas que permiten filtrar listas. REMOVE-IF elimina todos los elementos que
satisfacen el predicado dado. REMOVE-IF-NOT, en cambio elimina todos los elementos que
no lo satisfacen.
> (SETF digitos '(0 1 2 3 4 5 6 7 8 9))
(0 1 2 3 4 5 6 7 ...)
> (REMOVE-IF #'EVENP digitos)
(1 3 5 7 9)
> (REMOVE-IF-NOT #'EVENP digitos)
(0 2 4 6 8)
8.3 COUNT-IF y FIND-IF
COUNT-IF cuenta los elementos de una lista, que satisfacen una determinada prueba.
> (COUNT-IF #'EVENP digitos)
5
> (COUNT-IF-NOT #'ZEROP digitos)
9
22 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
FIND-IF encuentra el primer elemento de una lista, que satisface una determinada prueba.
> (FIND-IF #'EVENP digitos)
0
> (FIND-IF #'ODDP digitos)
1
8.4 FUNCALL y APPLY
Aplica el valor de su primer argumento al valor de los otros argumentos. Usa tantos
argumentos como requiera el procedimiento mencionado, más uno para el nombre del
procedimiento. FUNCALL permite definir procedimientos que tengan procedimientos como
argumentos.
> (FUNCALL #'FIRST '(A B C D)) ; Equivale a: (FIRST '(A B C D))
A
> (FUNCALL #'+ '(1 2 3 4 5))
(1 2 3 4 5)
> (FUNCALL #'+ 1 2 3 4 5)
15
APPLY suele tener dos argumentos. Usa el valor de su primer argumento sobre los elementos
del valor de su segundo argumento, el cual debe ser una lista. La lista tiene tantos elementos
como requiera el procedimiento mencionado.
> (APPLY #'FIRST '((A B C D)))
A
> (APPLY #'+ '(1 2 3 4 5))
15
En los casos en que APPLY aparezca con más de dos argumentos, todos los argumentos
excepto el primero y el último se combinan en una lista, a la cual se añade el último
argumento.
> (APPLY #'+ 1 2 3 '(4 5)) ; La lista de argumentos dados a + es
15 ; (APPEND (LIST 1 2 3) '(4 5))
8.5 FUNCIONES ANÓNIMAS (LAMBDA)
Para los casos en que las funciones definidas por el usuario son utilizadas una sola vez, es
preferible definir funciones anónimas. Las funciones anónimas son como las otras funciones
del LISP, excepto que no tienen asignado un nombre y se las usa una vez. Las funciones
anónimas son definidas mediante la expresión LAMBDA.
> (SETF colores '(azul verde rojo ))
(AZUL VERDE ROJO)
> ((LAMBDA (lista) (FIRST (REST lista))) colores)
VERDE
> (SETF aves '(gallo paloma pavo))
felinos '(león tigre pantera)
mascotas '(perro gato loro)
(PERRO GATO LORO)
> (SETF animales (LIST aves felinos mascotas))
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 23
((GALLO PALOMA PAVO) (LEóN TIGRE PANTERA) (PERRO GATO LORO))
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
> (MAPCAR #'(LAMBDA (lista) (FIRST (REST lista))) animales)
(PALOMA TIGRE GATO)
9. ITERACIÓN
Al igual que la recursión, la iteración es una estrategia general para controlar la evolución de
los cálculos. La iteración puede realizarse con varias primitivas que proporciona LISP.
9.1 DOTIMES
Permite escribir procedimientos sencillos con iteración controlada por un contador. La
plantilla general es la siguiente:
(DOTIMES (<parámetro de cuenta> <forma límite superior> <forma resultado>)
<cuerpo>)
Cuando empieza la ejecución de DOTIMES, la forma límite superior se evalúa produciendo
un número n. Entonces los números desde 0 hasta n-1 se asignan, uno después de otro, al
parámetro de cuenta. Para cada valor, se ejecuta el cuerpo. A la salida, la ligadura del
parámetro de cuenta se elimina y la forma resultado se evalúa, produciendo el valor de la
forma DOTIMES. Si DOTIMES no tiene forma resultado, devuelve NIL.
> (DEFUN FACTORIAL (num)
(LET ((resultado 1))
(DOTIMES (cuenta num resultado)
(SETF resultado (* (+ 1 cuenta) resultado)))))
FACTORIAL
> (FACTORIAL 0)
1
> (FACTORIAL 1)
1
> (FACTORIAL 5)
120
9.2 DOLIST
La primitiva DOLIST es similar a DOTIMES excepto que los parámetros de una forma lista
se asignan al parámetro de cuenta uno después del otro. La plantilla es la siguiente:
(DOLIST (<parámetro de cuenta> <forma lista> <forma resultado>)
<cuerpo>)
Para ilustrar el uso de DOLIST, a continuación se define la función REVERSE-DOLIST:
> (DEFUN REVERSE-DOLIST (lista)
(LET ((resultado NIL))
(DOLIST (cont lista resultado)
(SETF resultado (CONS cont resultado)))))
REVERSE-DOLIST
> (REVERSE lista1)
(F E D C B A)
> (REVERSE-DOLIST lista1)
(F E D C B A)
24 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
9.3 DO y DO*
La primitiva DO puede utilizarse para hacer iteraciones cuando DOTIMES y DOLIST no son
lo suficientemente flexibles. La plantilla de DO es la siguiente:
(DO ((<parámetro 1> <valor inicial 1> <forma de actualización 1>)
(<parámetro 2> <valor inicial 2> <forma de actualización 2>)
…
(<parámetro N> <valor inicial N> <forma de actualización N>))
(<prueba para finalizar> <formas intermedias, si existen> <forma resultado>)
<cuerpo>)
Los detalles de la operación de la primitiva DO, son los siguientes:
• La primera parte de una forma DO siempre es una lista de parámetros que se ligarán a
valores iniciales, al entrar al DO. Si no hay parámetros la lista vacía debe aparecer en la
primera posición. Las especificaciones para parámetros pueden incluir formas de
actualización, además de los nombres de variables y formas para valor inicial. Todas la
formas valor inicial se evalúan antes de ligarlas a los parámetros. De manera similar,
todas las formas de actualización se evalúan antes de hacer las nuevas asignaciones. Por
consiguiente se dice que DO maneja sus parámetros en paralelo. En este aspecto DO es
similar a LET, lo cual llega a ser crítico cuando un parámetro DO aparece en una forma de
inicialización o de actualización.
• La segunda parte de un DO establece cuándo termina el ciclo y qué valor se debe devolver.
Esta parte consta de una lista cuya forma inicial es una prueba para terminación. Las
formas que siguen en esta lista son evaluadas en orden cuando el valor de la forma de
prueba es diferente de NIL. El valor devuelto por DO es el valor de la última forma en
esta lista. Antes de cada pasada a través del cuerpo, se evalúa la prueba, incluyendo la
primera vez. Si sólo hay una forma, ésta es la prueba y DO devuelve NIL.
• La tercera parte de una forma DO, el cuerpo, consta de formas que son evaluadas
secuencialmente. Todos los valores se ignoran, es decir las evaluaciones sólo se hacen por
su posibles efectos secundarios. Siempre que dentro del cuerpo de un DO se encuentre una
expresión que inicie con RETURN, el DO termina inmediatamente. El valor retornado es
el indicado por la expresión RETURN.
La primitiva DO* es similar a DO, excepto que hace la ligadura secuencial de valores, en
lugar de hacerlo en paralelo. DO* es a DO, lo que LET es a LET*.
> (DEFUN REVERSE-DO (lista)
(DO ((list lista (REST list))
(resultado NIL (CONS (FIRST list) resultado)))
((ENDP list) resultado)))
REVERSE-DO
> (REVERSE lista1)
(F E D C B A)
> (REVERSE-DO lista1)
(F E D C B A)
9.4 LOOP
La primitiva LOOP, también se usa para iteración, pero a diferencia de las otras formas, sólo
tiene un cuerpo. Las formas del cuerpo son evaluadas una y otra vez. Cuando se encuentra
con una forma (RETURN <expresión>), la expresión es evaluada y LOOP termina retornando
el valor de la expresión.
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 25
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
9.5 PROG1 y PROGN
Las primitivas PROG1 y PROGN se utilizan para combinar explícitamente formas en
secuencia.
(PROG1 <forma de respuesta> <forma secundaria 1> … <forma secundaria N>)
(PROGN <forma secundaria 1> <forma secundaria 2> … <forma de respuesta>)
PROG1 establece como valor de respuesta para la forma completa la primera, mientras que
PROGN devuelve el resultado de la evaluación de la última.
La siguiente función calcula el promedio de una lista de números dada como argumento y
utiliza las formas LOOP y PROGN.
> (DEFUN promedio (lista)
(IF (ENDP lista) 0
(LET* ((total (FIRST lista)) (cuenta 1))
(LOOP
(SETF lista (REST lista))
(IF (ENDP lista) (RETURN (/ total cuenta))
(PROGN
(SETF total (+ total (FIRST lista)))
(SETF cuenta (+ cuenta 1))))))))
PROMEDIO
> (promedio '())
0
> (promedio '(3 5 7 9 11))
7
10. LECTURA Y ESCRITURA
Para establecer la comunicación entre los procedimientos y el usuario, LISP proporciona
varias primitivas tanto para proporcionar como para obtener información.
10.1 PRINT, PRIN1, PRINC y TERPRI
La primitiva PRINT evalúa su argumento y lo imprime en una nueva línea, seguido por un
espacio en blanco. El valor devuelto por PRINT es el valor de su argumento. Ejemplos:
> (SETF paciente '((nombre Andrade) (síntomas (fiebre comezón náusea))))
((NOMBRE ANDRADE) (SíNTOMAS (FIEBRE COMEZóN NáUSEA)))
> (PRINT paciente)
((NOMBRE ANDRADE) (SíNTOMAS (FIEBRE COMEZóN NáUSEA))) ; Acción de PRINT
((NOMBRE ANDRADE) (SíNTOMAS (FIEBRE COMEZóN NáUSEA))) ; Valor retornado por PRINT
> (DEFUN reporte (paciente)
(PROGN (PRINT (LIST 'Paciente (SECOND (ASSOC 'nombre paciente))
'presenta (LENGTH (SECOND (ASSOC 'síntomas paciente)))
'síntomas (SECOND (ASSOC 'síntomas paciente)))) NIL))
REPORTE
> (reporte paciente)
(PACIENTE ANDRADE PRESENTA 3 SíNTOMAS (FIEBRE COMEZóN NáUSEA)) ; Acción de
PRINT
NIL ; Valor retornado por PROGN
PRINT puede imprimir también cadenas, otro de los tipos de datos de LISP. Las cadenas son
secuencias de caracteres limitadas por comillas al inicio y al final.
26 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
> (PRINT "Hola que tal!")
"Hola que tal!" ; Acción de PRINT
"Hola que tal!" ; Valor retornado por PRINT
Hay otras primitivas derivadas de PRINT que están disponibles para asistir en las labores de
presentación de mensajes al usuario:
• PRIN1 es igual a PRINT, excepto que no imprime en una línea nueva, ni pone un espacio
al final de la línea.
• PRINC imprime la cadena dada como argumento sin incluír las comillas, ni retorno ni
espacio en blanco al final.
• TERPRI no requiere de argumentos y su efecto es forzar un cambio de línea.
El siguiente ejemplo ilustra el efecto de estas primitivas:
> (DEFUN media4 (uno dos tres cuatro)
(PRINT "El promedio de:")
(TERPRI)
(PRIN1 uno)
(PRINC " ")
(PRIN1 dos)
(PRINC " ")
(PRIN1 tres)
(PRINC " ")
(PRIN1 cuatro)
(TERPRI)
(PRINC "Da como resultado:")
(/ (+ uno dos tres cuatro) 4))
MEDIA4
> (MEDIA4 3 5 7 9)
"El promedio de:"
3 5 7 9
Da como resultado:
6
10.2 READ
LISP se detiene cuando encuentra la primitiva READ, espera que se digite en el teclado una
expresión. READ no imprime ningún mensaje, por lo que necesario utilizar una forma
PRINT, para poner un mensaje al usuario indicando el tipo de respuesta que se espera.
> (PROGN (SETF nombre NIL) (PRINT "Ingresar un nombre:")
(SETF nombre (READ)) (PRINT (APPEND '(El nombre es) (LIST nombre))) NIL)
"Ingresar un nombre:" Marcelo
(EL NOMBRE ES MARCELO)
NIL
10.3 FORMAT
La primitiva FORMAT permite imprimir mensajes más elegantes, nítidos y similares a
oraciones; conteniendo letras mayúsculas, minúsculas, y signos de puntuación.
> (FORMAT T "Hola que tal!")Hola que tal! ;Impresión de FORMAT
NIL ;El valor de FORMAT es NIL
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 27
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
La letra T indica a FORMAT que imprima en el terminal. Para imprimir la cadena de
caracteres en una nueva línea, se utiliza la directiva %. El signo ~ introduce una directiva. La
directiva & también le dice a FORMAT que empiece en una nueva línea, pero no lo hace si ya
hay una nueva línea.
> (PROGN (FORMAT T "~%Hola que tal!~%")
(FORMAT T "~%Esta línea se escribió luego de 1 línea en blanco. ~%")
(FORMAT T "~&Pero esta línea está precedida por la directiva &."))
Hola que tal!
Esta línea se escribió luego de 1 línea en blanco.
Pero esta línea está precedida por la directiva &.
NIL
La directiva A, indica a FORMAT que debe insertar el valor del argumento adicional que
aparece después de la cadena de caracteres de FORMAT.
> (LET ((nombre NIL))
(FORMAT T "~%Ingresar un nombre: ")
(SETF nombre (READ))
(FORMAT T "~%El nombre ingresado fue: ~A." nombre))
Ingresar un nombre: Roberto
El nombre ingresado fue: ROBERTO.
NIL
10.4 WITH-OPEN-FILE
Esta primitiva crea flujos, liga variables a ellos y se conecta a archivos. Conceptualmente, los
flujos son objetos LISP que sirven como fuentes o suministros de datos. Los flujos pueden
conectarse a archivos en uno de sus extremos.
Los flujos conectados a archivos que proporcionan datos se llaman flujos de entrada. Los
flujos de entrada están involucrados con las formas READ. Los flujos conectados a archivos
que reciben datos se llaman flujos de salida. Estos flujos están involucrados con las formas
PRINT y FORMAT.
La plantilla para WITH-OPEN-FILE permite la especificación de tres cosas: el nombre de la
variable que se va a ligar al flujo, el nombre del archivo al cual se va a conectar el flujo; y la
indicación si el flujo es de entrada o de salida.
(WITH-OPEN-FILE (<nombre del flujo>
<especificación del archivo>
:direction :input)
…
(READ <nombre del flujo> ‘eof) ; leer datos del flujo de entrada, hasta el final del archivo (eof)
…)
(WITH-OPEN-FILE (<nombre del flujo>
<especificación del archivo>
:direction :output)
…
(PRINT <expresión para imprimir> <nombre del flujo>)
…)
28 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
10.5 ELT
Es un acrónimo de ELemenTo. Se desempeña tanto con listas, como con cadenas. Recibe
dos argumentos:
• Si el primer argumento es una lista, devuelve el elemento especificado por su segundo
argumento.
• Si el primer argumento es una cadena, devuelve el carácter especificado por su segundo
argumento.
El primer elemento se especifica con el número cero (0).
> (ELT '(a b c) 0)
A
> (ELT '(a b c) 2)
C
> (ELT "abc" 0)
#a
> (ELT "abc" 2)
#c
Las primitivas LENGTH y REVERSE, también pueden operar con cadenas lo mismo que con
listas.
> (LENGTH "Politécnica Nacional")
20
> (REVERSE "Politécnica Nacional")
"lanoicaN acincétiloP"
10.6 STRING= y STRING-EQUAL
Estas primitivas se utilizan para determinar si dos cadenas son iguales. STRING= detecta la
diferencia entre mayúsculas y minúsculas, STRING-EQUAL no.
> (STRING= "abc" "xyz")
NIL
> (STRING= "abc" "abc")
T
> (STRING= "abc" "ABC")
NIL
> (STRING-EQUAL "abc" "xyz")
NIL
> (STRING-EQUAL "abc" "abc")
T
> (STRING-EQUAL "abc" "ABC")
T
10.7 CHAR= y CHAR-EQUAL
Estas primitivas permiten determinar si dos caracteres son iguales. CHAR= detecta la
diferencia entre mayúsculas y minúsculas; CHAR-EQUAL, no.
> (CHAR= #a #b)
NIL
> (CHAR= #a #a)
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 29
PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES
T
> (CHAR= #a #A)
NIL
> (CHAR-EQUAL #a #b)
NIL
> (CHAR-EQUAL #a #a)
T
> (CHAR-EQUAL #a #A)
T
10.8 SEARCH
Se utiliza para determinar si una cadena está contenida en otra. Si el primer argumento de
SEARCH está contenido en el segundo, el resultado es la posición donde empieza la
correspondencia. De otra forma SEARCH devuelve NIL.
> (SEARCH "razones" "Corazones no entienden razones")
2
> (SEARCH "tienden" "Corazones no entienden razones")
15
> (SEARCH "corazones" "Corazones no entienden razones")
NIL
> (SEARCH "corazones" "Corazones no entienden razones" :TEST #'CHAR-EQUAL)
0
Al igual que LENGTH, REVERSE y ELT, SEARCH es también una primitiva que opera
tanto con listas como con cadenas.
> (SEARCH '(razones) '(Corazones no entienden razones))
3
> (SEARCH '(tienden) '(Corazones no entienden razones))
NIL
> (SEARCH '(corazones) '(Corazones no entienden razones))
0
10.9 READ-CHAR
Lee un sólo carácter, ya sea del terminal o de un archivo.
> (READ-CHAR)H
#H
> (READ-CHAR)m
#m
10.10 READ-LINE
Lee una cadena de caracteres hasta cuando aparece el carácter de cambio de línea
(<ENTER>) o el carácter de final de archivo (EOF). Retorna dos valores: La línea de
caracteres leídos y el valor T.
> (READ-LINE)Mientras leía esta línea de pronto me encontré con el final
"Mientras leía esta línea de pronto me encontré con el final"
T
30 Junio, 2003 Hugo A. Banda Gamboa, PhD,
MSc.
SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP
A continuación se definen dos procedimientos, para ilustrar el uso de las formas de entrada y
salida: LEER-TEXTO y BUSCAR-TEXTO. Para probar estas funciones, se supone que en el
directorio de trabajo del LISP, existe un archivo de texto llamado “buscatxt.txt”.
> (DEFUN leer-texto (archivo)
(WITH-OPEN-FILE (datos archivo :direction :input)
(DO ((línea (READ-LINE datos NIL) (READ-LINE datos NIL)))
((NOT línea) T)
(FORMAT T "~% ~A" línea))))
LEER-TEXTO
> (leer-texto "buscatxt.txt")
BUSCAR-TEXTO es un procedimiento que busca a través de tal archivo una línea
que contenga una subcadena en particular, después de lo cual imprime la
línea completa. WITH-OPEN-FILE construye el flujo apropiado y READ-LINE lee
el archivo línea por línea. SEARCH prueba cada línea hasta encontrar una que
corresponda con el texto dado, hecho lo cual, FORMAT imprime la línea.
T
> (DEFUN buscar-texto (texto archivo)
(WITH-OPEN-FILE (datos archivo :direction :input)
(DO ((línea (READ-LINE datos NIL) (READ-LINE datos NIL)))
((NOT línea) (FORMAT T "~%No hay tal texto en: ~A" archivo))
(WHEN (SEARCH texto línea :TEST #'CHAR-EQUAL)
(FORMAT T "~% ~A" línea)
(RETURN T)))))
BUSCAR-TEXTO
> (BUSCAR-TEXTO "WITH-OPEN-FILE" "buscatxt.txt")
línea completa. WITH-OPEN-FILE construye el flujo apropiado y READ-LINE lee
T
11. BIBLIOGRAFÍA
[1] Bahrami A. Designing Artificial Intelligence Based Software. Sigma Press,
Wilmslow, UK, 1988.
[2] Franz Inc. Allegro CL for Windows Volume 1: Getting Started, Ver 3.0. Franz Inc.,
USA, 1995.
[3] Graham P. ANSI Common Lisp. Prentice Hall, USA, 1996.
[4] Hekmatpour S. Introduction to LISP and Symbol Manipulation. Prentice Hall, UK,
1988.
[5] Winstanley G. Program Design for Knowledge Based Systems. Sigma Press,
Wilmslow, UK, 1987.
[6] Winston P H, Horn B K P. LISP, 3ra. Edición. Addison-Wesley Iberoamericana,
USA, 1991.
Hugo A. Banda Gamboa,
PhD, MSc.
Junio, 2003 31

Contenu connexe

Tendances

La práctica en el Desarrollo de Software: Una visión general!
La práctica en el Desarrollo de Software: Una visión general!La práctica en el Desarrollo de Software: Una visión general!
La práctica en el Desarrollo de Software: Una visión general!
Cristian Sánchez
 
Vistas arquitectonicas. _Ing Software
Vistas arquitectonicas. _Ing SoftwareVistas arquitectonicas. _Ing Software
Vistas arquitectonicas. _Ing Software
Roberth Loaiza
 
Recopilacion De Informacion De Ing.Sofware
Recopilacion De Informacion De Ing.SofwareRecopilacion De Informacion De Ing.Sofware
Recopilacion De Informacion De Ing.Sofware
carolina
 
modelos del proceso del software
 modelos del proceso del software  modelos del proceso del software
modelos del proceso del software
Brihany Rossell
 
Arquitecturas de pizarra o repositório
Arquitecturas de pizarra o repositórioArquitecturas de pizarra o repositório
Arquitecturas de pizarra o repositório
rehoscript
 
Modelos y capas de la ingenieria de software
Modelos y capas  de la ingenieria de softwareModelos y capas  de la ingenieria de software
Modelos y capas de la ingenieria de software
jhonatanalex
 

Tendances (20)

La práctica en el Desarrollo de Software: Una visión general!
La práctica en el Desarrollo de Software: Una visión general!La práctica en el Desarrollo de Software: Una visión general!
La práctica en el Desarrollo de Software: Una visión general!
 
Vistas arquitectonicas. _Ing Software
Vistas arquitectonicas. _Ing SoftwareVistas arquitectonicas. _Ing Software
Vistas arquitectonicas. _Ing Software
 
Metodologia xp cortesserranoeliud
Metodologia xp cortesserranoeliudMetodologia xp cortesserranoeliud
Metodologia xp cortesserranoeliud
 
Decompilador y metacompilador
Decompilador y metacompiladorDecompilador y metacompilador
Decompilador y metacompilador
 
Tipos de Software
Tipos de SoftwareTipos de Software
Tipos de Software
 
Conceptos basicos de analisis y diseño
Conceptos basicos de analisis y diseñoConceptos basicos de analisis y diseño
Conceptos basicos de analisis y diseño
 
Sistemas expertos y sus aplicaciones
Sistemas expertos y sus aplicacionesSistemas expertos y sus aplicaciones
Sistemas expertos y sus aplicaciones
 
Paradigmas programacion
Paradigmas programacionParadigmas programacion
Paradigmas programacion
 
Sistemas operativos distribuidos
Sistemas operativos distribuidosSistemas operativos distribuidos
Sistemas operativos distribuidos
 
Emu8086
Emu8086Emu8086
Emu8086
 
Caracteristicas de Ruby
Caracteristicas de RubyCaracteristicas de Ruby
Caracteristicas de Ruby
 
Analisis de sistema
Analisis de sistemaAnalisis de sistema
Analisis de sistema
 
Unidad 3 : Sistemas Operativos I
Unidad 3 : Sistemas Operativos IUnidad 3 : Sistemas Operativos I
Unidad 3 : Sistemas Operativos I
 
Recopilacion De Informacion De Ing.Sofware
Recopilacion De Informacion De Ing.SofwareRecopilacion De Informacion De Ing.Sofware
Recopilacion De Informacion De Ing.Sofware
 
Generaciones de los sistemas operativos
Generaciones de los sistemas operativosGeneraciones de los sistemas operativos
Generaciones de los sistemas operativos
 
Resumen de los capitulos i, ii, iii del libro kendall & kendall
Resumen de los capitulos i, ii, iii del libro kendall & kendallResumen de los capitulos i, ii, iii del libro kendall & kendall
Resumen de los capitulos i, ii, iii del libro kendall & kendall
 
Algoritmo SJF
Algoritmo SJFAlgoritmo SJF
Algoritmo SJF
 
modelos del proceso del software
 modelos del proceso del software  modelos del proceso del software
modelos del proceso del software
 
Arquitecturas de pizarra o repositório
Arquitecturas de pizarra o repositórioArquitecturas de pizarra o repositório
Arquitecturas de pizarra o repositório
 
Modelos y capas de la ingenieria de software
Modelos y capas  de la ingenieria de softwareModelos y capas  de la ingenieria de software
Modelos y capas de la ingenieria de software
 

Similaire à LISP

Boccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julio
Boccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julioBoccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julio
Boccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julio
Cristian Caiza
 
Proyecyo final de analisis estructurado
Proyecyo final de analisis estructuradoProyecyo final de analisis estructurado
Proyecyo final de analisis estructurado
Juan Jose Flores
 
Proyecyo final de analisis estructurado
Proyecyo final de analisis estructuradoProyecyo final de analisis estructurado
Proyecyo final de analisis estructurado
Juan Jose Flores
 
95870560 analisis-y-diseo-de-edificios-asistido-por-as
95870560 analisis-y-diseo-de-edificios-asistido-por-as95870560 analisis-y-diseo-de-edificios-asistido-por-as
95870560 analisis-y-diseo-de-edificios-asistido-por-as
benji_772
 
Analisis y diseã‘o de edificios asistido por computadoras
Analisis y diseã‘o de edificios asistido por computadorasAnalisis y diseã‘o de edificios asistido por computadoras
Analisis y diseã‘o de edificios asistido por computadoras
ingdeath
 
10 conceptos basicos_procesadores_lenguaje
10 conceptos basicos_procesadores_lenguaje10 conceptos basicos_procesadores_lenguaje
10 conceptos basicos_procesadores_lenguaje
Areli Gómez
 
estrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdfestrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdf
nicole668764
 
Algoritmos guia de maria hernandez
Algoritmos guia de maria hernandezAlgoritmos guia de maria hernandez
Algoritmos guia de maria hernandez
jackie_18
 
Trabajo colaborativo grupo 151
Trabajo colaborativo grupo 151Trabajo colaborativo grupo 151
Trabajo colaborativo grupo 151
tecnoeyca
 

Similaire à LISP (20)

Boccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julio
Boccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julioBoccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julio
Boccardo ruiz2018.usoder studioparaestadsticaunivariadaencienciassociales19julio
 
Proyecyo final de analisis estructurado
Proyecyo final de analisis estructuradoProyecyo final de analisis estructurado
Proyecyo final de analisis estructurado
 
Proyecyo final de analisis estructurado
Proyecyo final de analisis estructuradoProyecyo final de analisis estructurado
Proyecyo final de analisis estructurado
 
Algoritmos-resueltos-con-Python.pdf
Algoritmos-resueltos-con-Python.pdfAlgoritmos-resueltos-con-Python.pdf
Algoritmos-resueltos-con-Python.pdf
 
Algoritmos resueltos-con-python
Algoritmos resueltos-con-pythonAlgoritmos resueltos-con-python
Algoritmos resueltos-con-python
 
algoritmos-resueltos-con-python1.pdf
algoritmos-resueltos-con-python1.pdfalgoritmos-resueltos-con-python1.pdf
algoritmos-resueltos-con-python1.pdf
 
Algoritmos-resueltos-con-Python.pdf
Algoritmos-resueltos-con-Python.pdfAlgoritmos-resueltos-con-Python.pdf
Algoritmos-resueltos-con-Python.pdf
 
Unidd 3
Unidd 3Unidd 3
Unidd 3
 
Organizador de info herramientas case
Organizador de info herramientas caseOrganizador de info herramientas case
Organizador de info herramientas case
 
95870560 analisis-y-diseo-de-edificios-asistido-por-as
95870560 analisis-y-diseo-de-edificios-asistido-por-as95870560 analisis-y-diseo-de-edificios-asistido-por-as
95870560 analisis-y-diseo-de-edificios-asistido-por-as
 
Analisis y diseã‘o de edificios asistido por computadoras
Analisis y diseã‘o de edificios asistido por computadorasAnalisis y diseã‘o de edificios asistido por computadoras
Analisis y diseã‘o de edificios asistido por computadoras
 
estrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdfestrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdf
 
10 conceptos basicos_procesadores_lenguaje
10 conceptos basicos_procesadores_lenguaje10 conceptos basicos_procesadores_lenguaje
10 conceptos basicos_procesadores_lenguaje
 
estrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdfestrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdf
 
estrategias de apoyo nicole ochoa 2.pdf
estrategias de apoyo nicole ochoa 2.pdfestrategias de apoyo nicole ochoa 2.pdf
estrategias de apoyo nicole ochoa 2.pdf
 
estrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdfestrategias de apoyo nicole ochoa.pdf
estrategias de apoyo nicole ochoa.pdf
 
Algoritmos guia de maria hernandez
Algoritmos guia de maria hernandezAlgoritmos guia de maria hernandez
Algoritmos guia de maria hernandez
 
ArduProcessing
ArduProcessingArduProcessing
ArduProcessing
 
Trabajo colaborativo grupo 151
Trabajo colaborativo grupo 151Trabajo colaborativo grupo 151
Trabajo colaborativo grupo 151
 
Portafolio final de tecnologia. 1
Portafolio final de tecnologia. 1Portafolio final de tecnologia. 1
Portafolio final de tecnologia. 1
 

Plus de Alex Pin

Agenda de Datos Personales en LISP
Agenda de Datos Personales en LISPAgenda de Datos Personales en LISP
Agenda de Datos Personales en LISP
Alex Pin
 
Descripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRS
Descripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRSDescripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRS
Descripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRS
Alex Pin
 
Trabajo symbian
Trabajo symbianTrabajo symbian
Trabajo symbian
Alex Pin
 
Torres de hanoi
Torres de hanoiTorres de hanoi
Torres de hanoi
Alex Pin
 
manufactura inteligente
manufactura inteligentemanufactura inteligente
manufactura inteligente
Alex Pin
 
Arboles avl
Arboles avlArboles avl
Arboles avl
Alex Pin
 
Pilas y Colas
Pilas y ColasPilas y Colas
Pilas y Colas
Alex Pin
 

Plus de Alex Pin (20)

Configuracion de redes vlan
Configuracion de redes vlanConfiguracion de redes vlan
Configuracion de redes vlan
 
Agenda de Datos Personales en LISP
Agenda de Datos Personales en LISPAgenda de Datos Personales en LISP
Agenda de Datos Personales en LISP
 
ingeniera social
ingeniera socialingeniera social
ingeniera social
 
Ingeniera social carlosbiscione
Ingeniera social carlosbiscioneIngeniera social carlosbiscione
Ingeniera social carlosbiscione
 
programación en prolog
programación en prologprogramación en prolog
programación en prolog
 
seguridad informática
seguridad informáticaseguridad informática
seguridad informática
 
Administración de sistemas linux
Administración de sistemas linuxAdministración de sistemas linux
Administración de sistemas linux
 
Introducción a la_neuro_computación
Introducción a la_neuro_computaciónIntroducción a la_neuro_computación
Introducción a la_neuro_computación
 
Catedral y bazar una visión analítica de la técnica de desarrollo open source
Catedral y bazar una visión analítica de la técnica de desarrollo open source Catedral y bazar una visión analítica de la técnica de desarrollo open source
Catedral y bazar una visión analítica de la técnica de desarrollo open source
 
Analisis y-modelado-de-amenazas
Analisis y-modelado-de-amenazasAnalisis y-modelado-de-amenazas
Analisis y-modelado-de-amenazas
 
Comparacion de las estructuras de bloque de los sistemas operativos symbian, ...
Comparacion de las estructuras de bloque de los sistemas operativos symbian, ...Comparacion de las estructuras de bloque de los sistemas operativos symbian, ...
Comparacion de las estructuras de bloque de los sistemas operativos symbian, ...
 
Descripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRS
Descripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRSDescripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRS
Descripcion del S.O. Symbian para el desarrollo de aplicaciones en la red GPRS
 
Trabajo symbian
Trabajo symbianTrabajo symbian
Trabajo symbian
 
Torres de hanoi
Torres de hanoiTorres de hanoi
Torres de hanoi
 
manufactura inteligente
manufactura inteligentemanufactura inteligente
manufactura inteligente
 
Arboles avl
Arboles avlArboles avl
Arboles avl
 
NASM
NASM NASM
NASM
 
Tutorial perl en linux
Tutorial perl en linuxTutorial perl en linux
Tutorial perl en linux
 
Informe minishell
Informe minishellInforme minishell
Informe minishell
 
Pilas y Colas
Pilas y ColasPilas y Colas
Pilas y Colas
 

Dernier

2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx
2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx
2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx
naomivillacres0
 
253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION
253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION
253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION
ArtemisaReateguiCaro
 

Dernier (10)

Técnica de apareo o emparejamiento en eppidemiologia
Técnica de apareo o emparejamiento en eppidemiologiaTécnica de apareo o emparejamiento en eppidemiologia
Técnica de apareo o emparejamiento en eppidemiologia
 
Mercado de trabajo y discapacidad. Inclusión laboral.
Mercado de trabajo y discapacidad.  Inclusión laboral.Mercado de trabajo y discapacidad.  Inclusión laboral.
Mercado de trabajo y discapacidad. Inclusión laboral.
 
Manual Corporativo Cafe Daelicia en pdf.
Manual Corporativo Cafe Daelicia en pdf.Manual Corporativo Cafe Daelicia en pdf.
Manual Corporativo Cafe Daelicia en pdf.
 
Patologia General DRA Tiñini Banknco.pdf
Patologia General DRA Tiñini Banknco.pdfPatologia General DRA Tiñini Banknco.pdf
Patologia General DRA Tiñini Banknco.pdf
 
2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx
2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx
2 CONCEPTOS BASICOS EN FARMACOLOGIA.pptx
 
Manual-de-instalaciones-sanitarias-modulo-2-Minedu.pdf
Manual-de-instalaciones-sanitarias-modulo-2-Minedu.pdfManual-de-instalaciones-sanitarias-modulo-2-Minedu.pdf
Manual-de-instalaciones-sanitarias-modulo-2-Minedu.pdf
 
Retiro de los fondo AFP en el Perú Año 2024
Retiro de los fondo AFP en el Perú Año 2024Retiro de los fondo AFP en el Perú Año 2024
Retiro de los fondo AFP en el Perú Año 2024
 
DECRETO 356 vigilancia y seguridad privada
DECRETO 356 vigilancia  y seguridad privadaDECRETO 356 vigilancia  y seguridad privada
DECRETO 356 vigilancia y seguridad privada
 
Explora el boletín del 3 de mayo de 2024
Explora el boletín del 3 de mayo de 2024Explora el boletín del 3 de mayo de 2024
Explora el boletín del 3 de mayo de 2024
 
253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION
253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION
253.CUIDARTE SAN MARTIN PARA UNA MEJOR FORMACION
 

LISP

  • 1. ESCUELA POLITÉCNICA NACIONAL DEPARTAMENTO DE INFORMÁTICA Y CIENCIAS DE LA COMPUTACIÓN PROGRAMACIÓN EN LISP NIVEL BÁSICO Hugo A. Banda Gamboa PhD, MSc. 2003
  • 2.
  • 3. PRESENTACIÓN Este manual de programación utilizando el lenguaje LISP, fue desarrollado como una guía para mis estudiantes de la materia Sistemas Inteligentes, que se dicta en el Programa de Ingeniería en Sistemas Informáticos y de Computación de la Escuela Politécnica Nacional. Básicamente, es una condensación del libro clásico LISP, de Patrick Hendry Winston y Berthold Klaus Paul Horn. También se incluyen aportes de otras obras consultadas, que se indican en la sección BIBLIOGRAFÍA, y experiencias recogidas durante 14 semestres que he dictado esta materia. Espero que esta obra cumpla con su propósito de incentivar al estudio y al trabajo experimental en las técnicas y aplicaciones de la inteligencia artificial, utilizando LISP. La referencia al interprete LISP y los ejemplos han sido desarrollados utilizando el producto ALLEGRO CL for WINDOWS, Version 5.0 Professional, de la casa: Franz Inc. 1995 University Avenue, Berkeley CA 94704, USA. Para los estudiantes que estén interesados en obtener una versión limitada del Allegro CL, en forma gratuita, pueden hacerlo de la página WWW que mantiene Franz Inc. Su dirección es: http://www.franz.com Finalmente, deseo dejar constancia de mi agradecimiento a mi familia, Paty y Huguito, quienes generosamente me dieron su apoyo para la realización de esta obra. Quito, junio de 2003 Atentamente, Hugo A. Banda Gamboa, PhD, MSc.. Profesor Principal Departamento de Informática y Ciencias de la Computación ESCUELA POLITÉCNICA NACIONAL Quito - Ecuador
  • 4.
  • 5. SISTEMAS DE INTELIGENCIA ARTIFICIAL PROGRAMACIÓN EN LISP CONTENIDO 1. INTRODUCCIÓN ....................................................................................................................................... 1 2. TIPOS DE DATOS...................................................................................................................................... 1 3. INTERACCIÓN CON EL INTÉRPRETE LISP...................................................................................... 2 4. PRINCIPALES FUNCIONES PRIMITIVAS .......................................................................................... 3 4.1 SETF .................................................................................................................................................... 4 4.2 FIRST (CAR)....................................................................................................................................... 4 4.3 REST (CDR) ........................................................................................................................................ 4 4.4 NTHCDR ............................................................................................................................................. 4 4.5 BUTLAST............................................................................................................................................ 5 4.6 LAST.................................................................................................................................................... 5 4.7 LENGTH Y REVERSE........................................................................................................................ 5 4.8 CONS................................................................................................................................................... 5 4.9 APPEND .............................................................................................................................................. 6 4.10 LIST ..................................................................................................................................................... 6 4.11 REMOVE............................................................................................................................................. 6 4.12 ASSOC................................................................................................................................................. 6 4.13 SUMA, RESTA, PRODUCTO Y DIVISIÓN ...................................................................................... 7 4.14 FLOAT................................................................................................................................................. 7 4.15 ROUND................................................................................................................................................ 8 4.16 TRUNCATE ........................................................................................................................................ 8 4.17 REM..................................................................................................................................................... 8 4.18 MAX Y MIN......................................................................................................................................... 8 4.19 EXPT.................................................................................................................................................... 9 4.20 SQRT.................................................................................................................................................... 9 4.21 ABS...................................................................................................................................................... 9 5. DEFINICIÓN DE PROCEDIMIENTOS Y LIGADURA........................................................................ 9 5.1 DEFUN .............................................................................................................................................. 10 5.2 LET .................................................................................................................................................... 10 5.3 LET* .................................................................................................................................................. 11 6. PREDICADOS Y CONDICIONALES.................................................................................................... 11 6.1 =, EQ, EQL Y EQUAL....................................................................................................................... 11 6.2 MEMBER........................................................................................................................................... 12 6.3 ATOM, NUMBERP, SYMBOLP Y LISTP ....................................................................................... 13 6.4 NULL Y ENDP................................................................................................................................... 14 6.5 ZEROP, PLUSP, MINUSP, EVENP, ODDP, > Y <.......................................................................... 14 6.6 AND, OR Y NOT ............................................................................................................................... 14 6.7 IF, WHEN Y UNLESS....................................................................................................................... 15 6.8 COND ................................................................................................................................................ 15 6.9 CASE.................................................................................................................................................. 16 7. ABSTRACCIÓN DE PROCEDIMIENTOS Y RECURSIÓN .............................................................. 17 7.1 PROCEDIMIENTOS RECURSIVOS ............................................................................................... 17 7.2 PARÁMETROS OPCIONALES ....................................................................................................... 20 7.3 PARÁMETROS RESTANTES ......................................................................................................... 20 7.4 PARÁMETROS CLAVE................................................................................................................... 21 7.5 PARÁMETROS AUXILIARES........................................................................................................ 21 8. TRANSFORMACIONES Y FUNCIONES ANÓNIMAS...................................................................... 22 i
  • 6. PROGRAMACIÓN EN LISP SISTEMAS DE INTELIGENCIA ARTIFICIAL 8.1 MAPCAR ...........................................................................................................................................22 8.2 REMOVE-IF Y REMOVE-IF-NOT...................................................................................................22 8.3 COUNT-IF Y FIND-IF .......................................................................................................................22 8.4 FUNCALL Y APPLY.........................................................................................................................23 8.5 FUNCIONES ANÓNIMAS (LAMBDA) ..........................................................................................23 9. ITERACIÓN ..............................................................................................................................................24 9.1 DOTIMES ..........................................................................................................................................24 9.2 DOLIST..............................................................................................................................................24 9.3 DO Y DO* ..........................................................................................................................................25 9.4 LOOP..................................................................................................................................................25 9.5 PROG1 Y PROGN..............................................................................................................................26 10. LECTURA Y ESCRITURA.................................................................................................................26 10.1 PRINT, PRIN1, PRINC Y TERPRI....................................................................................................26 10.2 READ .................................................................................................................................................27 10.3 FORMAT ...........................................................................................................................................27 10.4 WITH-OPEN-FILE............................................................................................................................28 10.5 ELT.....................................................................................................................................................29 10.6 STRING= Y STRING-EQUAL..........................................................................................................29 10.7 CHAR= Y CHAR-EQUAL.................................................................................................................29 10.8 SEARCH ............................................................................................................................................30 10.9 READ-CHAR.....................................................................................................................................30 10.10 READ-LINE.......................................................................................................................................30 11. BIBLIOGRAFÍA...................................................................................................................................31 ii
  • 7. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP PROGRAMACIÓN EN LISP 1. INTRODUCCIÓN La manipulación simbólica es el bloque constructivo básico de los programas de inteligencia artificial. Programas para manipulación simbólica pueden reconocer expresiones simbólicas particulares y pueden dividir expresiones para construir nuevas. LISP es un lenguaje diseñado para manipulación simbólica, en contraste con los lenguajes de programación convencionales que están primordialmente diseñados para procesamiento numérico. En lugar de manipular estructuras de datos numéricos (como números y arreglos), los programas en LISP típicamente manipulan estructuras de datos simbólicos (como palabras y oraciones). Lo que distingue a LISP de otros lenguajes de programación, es que está diseñado para evolucionar. Ofrece construcciones especiales que permite escribir programas que escriben programas. A continuación se presenta una colección de lecciones diseñadas para aprender los fundamentos de programación utilizando Common LISP. Este es un poderoso lenguaje de inteligencia artificial rico en construcciones y funciones para operar sobre estructuras de datos creados por el usuario. Sin embargo, existe un pequeño subconjunto del Common LISP, que se puede utilizar para ilustrar muchos de los conceptos fundamentales de programación, requeridos para comprender el lenguaje LISP. 2. TIPOS DE DATOS En LISP, virtualmente cualquier estructura de datos puede ser representada como un objeto. LISP utiliza dos tipos de objetos: átomos y listas. Los átomos son objetos simples que pueden ser simbólicos o numéricos. Los átomos numéricos o simplemente números, pueden ser enteros, racionales, reales y complejos, tanto positivos como negativos. Por ejemplo: 12 2.5 -30 0.005 -8.0 1997 2/3 #C(0 2) -5/8 Los átomos simbólicos o simplemente símbolos, pueden incluir palabras, letras y caracteres especiales. Por ejemplo: Hola P200 Esto_es_un_átomo + - / * Una lista es un objeto compuesto que consiste de cero o más átomos o listas encerradas entre paréntesis. Por ejemplo: () (9) (Politécnica Nacional) (+ 12 76) (colores (rojo azul verde)) A los átomos y listas se los denomina expresiones simbólicas o simplemente expresiones. Estas expresiones constituyen los tipos de datos. En LISP, los valores son los que tienen Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 1
  • 8. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES tipos, no las variables. No es necesario declarar los tipos de variables porque todas las variables pueden contener objetos de cualquier tipo. Las ocurrencias específicas de los diversos tipos de datos se denominan objetos. Así, 1997 es un objeto que pertenece al tipo de datos número, HOLA es un objeto del tipo de datos símbolo y (A B C) es un objeto del tipo de datos lista. LISP tiene también muchos otros tipos de datos, incluyendo caracteres, arreglos, cadenas y estructuras. La estructura básica, de mayor importancia en LISP, es la lista. Una lista puede utilizarse para representar una estructura de árbol. Por ejemplo la siguiente lista representa la descripción del árbol de la Figura 1. ( X ( A ) ( B ( E ) ( F ) ( G ) ) ( C ) ( D ) ) Figura. 1. Representación en árbol E F G DCA B X Las listas también se emplean en procedimientos y funciones. A LISP se lo puede considerar como un lenguaje de programación funcional porque utiliza funciones para manipular las estructuras de expresiones simbólicas. 3. INTERACCIÓN CON EL INTÉRPRETE LISP La interacción con LISP es muy similar a la que se realiza cuando se emplea una calculadora de bolsillo. En primer lugar, ante el símbolo del interprete (>) se ingresa una expresión, luego LISP lee la expresión, la evalúa y entrega el resultado. Para prevenir la evaluación de una expresión, se debe poner antes de la expresión el apóstrofe ( ' ). Si se ingresa el nombre de un símbolo sin el apóstrofe, el sistema retorna el valor asociado al símbolo si está definido, caso contrario despliega un mensaje de error. Por ejemplo: > HOLA ;; Error: Unbound variable HOLA in #<function 1 #x811040> ;; Returning to Top Level > 'HOLA HOLA > 2 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 9. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP Por convención, ciertos átomos se evalúan a sí mismos. Entre los átomos simbólicos, T (VERDADERO) y NIL (NULO) siempre se auto evalúan. También los átomos numéricos se evalúan a sí mismos: > t T > nil NIL > 34 34 > 19.45 19.45 > Las listas se ingresan encerrando sus elementos entre paréntesis. No importa lo que esté en la lista, LISP trata de evaluarla asumiendo que el primer elemento es el nombre de una función o de un procedimiento y que los otros elementos son sus argumentos. Dado un conjunto ordenado de objetos, una función LISP retorna un valor único, basado en sus argumentos. Pero si se antepone a la lista el apóstrofe, el sistema responde con la misma lista. Por ejemplo: > (A) ;; Error: Call to undefined function A in #<function 0 #xE72950> ;; Returning to Top Level > '(A) (A) > (A B) ;; Error: Unbound variable B in #<function 0 #xE7B944> ;; Returning to Top Level > '(A B) (A B) Existen dos tipos de funciones en LISP, las definidas por el sistema y las definidas por el usuario. Las funciones definidas por el sistema se las denomina también funciones primitivas. Escribir programas en LISP consiste en utilizar las funciones primitivas y definir funciones adicionales para realizar alguna tarea deseada. 4. PRINCIPALES FUNCIONES PRIMITIVAS LISP es un acrónimo de LISt Processing. Como es de esperar, LISP proporciona funciones primitivas para operar sobre listas de objetos. En LISP, las llamadas a funciones utilizan el siguiente formato: (nombre arg1 arg2 … argN) Donde nombre corresponde al nombre de la función, arg1 es el primer argumento, arg2 es el segundo argumento, y así sucesivamente. Al proceso de reservar un lugar en la memoria del computador con el fin de almacenar un valor para un símbolo se lo denomina ligadura; y al proceso de almacenar un valor en ese lugar asignación. El proceso de recuperar un valor de ese lugar es un tipo de evaluación. Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 3
  • 10. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES 4.1 SETF LISP asocia símbolos conforme los encuentra. Una manera de asignar un valor a un símbolo es mediante la función primitiva SETF. Esta función hace que el valor de su segundo argumento se asigne a su primer argumento. > (SETF AÑO '1997) 1997 > AÑO 1997 > (SETF animales '(perro gato león tigre)) (PERRO GATO LEóN TIGRE) > animales (PERRO GATO LEóN TIGRE) Se pueden incluir varios pares símbolo - valor en una sola instrucción SETF. Los argumentos que están en posición impar no se evalúan, sólo los que están en lugares pares. La función devuelve el valor del argumento final. > (SETF FELINOS '(GATO LEÓN TIGRE) ROEDORES '(RATÓN CONEJO CUY)) (RATÓN CONEJO CUY) > FELINOS (GATO LEÓN TIGRE) > ROEDORES (RATÓN CONEJO CUY) Una de las operaciones más comunes es la extracción o selección de uno de los miembros de una lista. Las funciones que realizan esta operación de denominan funciones selectoras. Las principales funciones selectoras son: FIRST y REST. Los nombres dados a estas funciones en implementaciones antiguas son: CAR y CDR respectivamente. 4.2 FIRST (CAR) Devuelve el primer objeto de una lista dada como argumento. > (FIRST '(amarillo azul rojo)) AMARILLO 4.3 REST (CDR) Hace el trabajo complementario a FIRST. Devuelve una lista que contiene todos los objetos de la lista original, excepto el primero. > (REST '(amarillo azul rojo)) (AZUL ROJO) 4.4 NTHCDR Elimina los n primeros elementos (primer argumento), de una lista dada como segundo argumento. Si el primer argumento de NTHCDR es mayor o igual que el número de elementos de la lista, retorna NIL. > (NTHCDR 2 '(amarillo azul rojo)) (ROJO) > (NTHCDR 3 '(amarillo azul rojo)) NIL 4 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 11. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP 4.5 BUTLAST Es similar a NTHCDR, sólo que en lugar de eliminar los primeros n elementos, elimina los n últimos. También difiere en el orden de los argumentos, la lista es el primer argumento y el valor de n es el segundo. Si no existe el segundo argumento, sólo se elimina el último elemento. > (BUTLAST '(amarillo azul rojo) 2) (AMARILLO) > (BUTLAST '(amarillo azul rojo)) (AMARILLO AZUL) 4.6 LAST Devuelve una lista en la que se ha eliminado todos los elementos, excepto el último. > (LAST '(amarillo azul rojo)) (ROJO) Es importante notar que LAST devuelve una lista conteniendo al último elemento de la lista original. Para extraer el último elemento de la lista, se debe combinar FIRST y LAST: > (FIRST (LAST '(amarillo azul rojo))) ROJO El anterior ejemplo ilustra la posibilidad de utilizar el valor retornado por la llamada a una función como argumento para otra función. 4.7 LENGTH y REVERSE La primitiva LENGTH cuenta el número de elementos del nivel superior que hay en una lista, y REVERSE invierte el orden de estos. Ambas funciones consideran que su argumento es una lista de elementos, sin importar que estos sean listas o átomos. Cuando sus argumentos son listas cuyos objetos son listas, no se afectan a las sublistas. > (LENGTH '(amarillo azul rojo)) 3 > (LENGTH '((Pichincha Quito) (Azuay Cuenca) (Carchi Tulcán))) 3 > (REVERSE '(amarillo azul rojo)) (ROJO AZUL AMARILLO) > (REVERSE '((Pichincha Quito) (Azuay Cuenca) (Carchi Tulcán))) ((CARCHI TULCáN) (AZUAY CUENCA) (PICHINCHA QUITO)) LISP también proporciona funciones constructoras. Estas son: CONS, APPEND y LIST. 4.8 CONS Toma sólo 2 argumentos: una expresión y una lista. Retorna una nueva lista, donde el primer elemento es la expresión y los restantes son los de la lista dada como segundo argumento. > (CONS 'perro '(gato loro ratón)) (PERRO GATO LORO RATóN) > (CONS '(A B) '(X Y)) ((A B) X Y) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 5
  • 12. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES 4.9 APPEND Acepta una o más listas como argumentos. Retorna una lista en la que están combinados los elementos del nivel superior de las listas dadas como argumentos. > (APPEND '(perro) '(gato loro ratón)) (PERRO GATO LORO RATóN) > (APPEND '(A B) '(X Y)) (A B X Y) > (APPEND '(a) '(b c) '(w (x y) z)) (A B C W (X Y) Z) > 4.10 LIST Trabaja con uno o más argumentos. Su resultado es una nueva lista en la que cada uno de los argumentos se vuelve un elemento. > (LIST 'perro '(gato loro ratón)) (PERRO (GATO LORO RATóN)) > (LIST '(perro) '(gato loro ratón)) ((PERRO) (GATO LORO RATóN)) > (LIST 'perro 'gato 'loro 'ratón) (PERRO GATO LORO RATóN) 4.11 REMOVE Acepta dos argumentos: un símbolo y una lista. Retorna la lista dada como segundo argumento, en la que todas las ocurrencias en el nivel superior del símbolo dado como primer argumento ha sido removido. > (REMOVE 'd '(a (b c) d e f)) (A (B C) E F) > (REMOVE '(b c) '(a (b c) d e f)) (A (B C) D E F) > (REMOVE 'b '(a (b c) d e f)) (A (B C) D E F) > Es importante notar que las funciones CONS, APPEND, LIST y REMOVE no alteran el valor de los objetos utilizados como sus argumentos. 4.12 ASSOC Para acceder a sublistas, LISP proporciona la función ASSOC. Esta primitiva está especialmente diseñada para trabajar con listas de asociación. Una lista de asociación consta de una serie de sublistas. El primer elemento de cada sublista se utiliza como clave para recuperar la sublista completa. (ASSOC <clave> <lista de asociación>) La operación de esta primitiva se muestra en los siguientes ejemplos: > (SETF PC1 '((RAM 8KB) (DISCO 1.2GB)) PC2 '((RAM 32KB) (DISCO 2.0 GB))) ((RAM 32KB) (DISCO 2.0 GB)) 6 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 13. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP > (ASSOC 'RAM PC1) (RAM 8KB) > (ASSOC 'DISCO PC2) (DISCO 2.0 GB) ASSOC siempre retorna la sublista completa cuyo primer elemento es igual a la clave. En el caso de que más de una sublista cumpla con la condición, sólo devuelve la primera ocurrencia, el resto de sublistas permanecen ocultas. LISP también proporciona primitivas para operar sobre números enteros, racionales, reales y complejos: +, -, *, /, FLOAT, ROUND, MAX, MIN, EXPT, SQRT, ABS. 4.13 SUMA, RESTA, PRODUCTO y DIVISIÓN Las funciones suma ( + ), resta ( - ), producto (*) y división ( / ), pueden operar con uno o más argumentos. > (+ 1.5 5 3.9 12) 22.4 > (- 16 4.5) 11.5 > (* 2 3 4) 24 > (+ #C(0 2) #C(1 -3)) #C(1 -1) Cuando sus 2 argumentos son números enteros y no se dividen exactamente, la división retorna un número racional. Basta con que uno de sus argumentos sea un número real, la división dará como resultado también un número real. > (/ 3 4) 3/4 > (/ 3.0 4) 0.75 > (/ #C(3 4) #C(1 -1)) #C(-1/2 7/2) > (/ #C(3.0 4.0) #C(1.0 -1.0)) #C(-0.5 3.5) Si la función divisora sólo tiene un argumento, calcula el recíproco del número dado: > (/ 3) > 1/3 > (/ #C(-4 3)) #C(-4/25 -3/25) > (/ #C(-4.0 3.0)) #C(-0.16 -0.12) 4.14 FLOAT Cuando se desea obtener un resultado de punto flotante, se puede utilizar FLOAT, una primitiva que convierte su argumento en número real. > (FLOAT (/ 3 4)) 0.75 Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 7
  • 14. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES 4.15 ROUND Redondea el resultado de la división hacia el entero más cercano. ROUND entrega dos valores. El primero es el entero más cercano. Si el resulado está justo en el medio de dos valores enteros, retorna el numero par. El segundo valor es el residuo producido por la operación de redondeo. > (ROUND 0.99) 1 -0.01 > (ROUND -1.5) -2 0.5 > (ROUND 3 2) 2 -1 4.16 TRUNCATE Trunca el resultado de la división de sus argumentos, en dirección al entero más cercano al cero. Retorna dos valores: el entero con el mismo signo que el resultado de la división y el residuo producido por la operación de truncado. > (TRUNCATE 0.99) 0 0.99 > (TRUNCATE -1.5) -1 -0.5 > (TRUNCATE 3 2) 1 1 > 4.17 REM Toma dos argumentos y retorna el residuo de la división entre ellos. > (REM 17 6) 5 > (REM -17 6) -5 > (REM -17 -6) -5 > (REM 17 -6) 5 > 4.18 MAX y MIN Las primitivas MAX y MIN, retornan el máximo y el mínimo, respectivamente, dada una secuencia de números: > (MAX 2 5 3) 5 > (MIN 2 5 3) 2 8 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 15. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP 4.19 EXPT Calcula potencias elevando su primer argumento al segundo. Puede operar sobre números enteros y reales. > (EXPT 3 4) 81 > (EXPT 2.3 4.2) 33.0565032282171 4.20 SQRT SQRT extrae la raíz cuadrada de su argumento. Si el argumento es un número negativo, retorna un número complejo: > (SQRT 27) 5.19615242270663 > (SQRT -25) #C(0.0 5.0) 4.21 ABS Retorna el valor absoluto de su argumento: > (ABS -34) 34 5. DEFINICIÓN DE PROCEDIMIENTOS Y LIGADURA Una de las principales fortalezas de LISP es que los programas pueden ser usados como datos para otros programas. Esto se deriva del hecho de que los datos y los programas en LISP son representados de la misma forma. Los programas son construidos en base a formas y funciones. Las formas son las unidades fundamentales de los programas en LISP, los cuales son evaluados para retornar uno o más valores y también pueden producir otros efectos colaterales. Algunas pueden llamar a funciones. A su vez, una función es una colección de formas que son evaluadas cuando se llama a la función. Las funciones son llamadas con sus respectivos argumentos. A las funciones se las puede dar nombres utilizando símbolos. Para definir una función o procedimiento, LISP necesita conocer 3 cosas: • El nombre de la función o procedimiento. • Los de argumentos que necesita. • La tarea que la función o procedimiento debe realizar A los argumentos de la función o procedimiento se los denomina parámetros. Los parámetros de un procedimiento son variables ligadas a él. Una variable es un símbolo con el que se designa algún lugar de memoria destinado para almacenar un valor. Al iniciar la ejecución de la función, a cada parámetro se le asigna un valor. La tarea definida para ser realizada, constituye el cuerpo del procedimiento. El cuerpo de un procedimiento consta de las formas que son evaluadas cuando éste se utiliza. Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 9
  • 16. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES Para definir procedimientos LISP proporciona la primitiva DEFUN, un acrónimo de DEFinir FUNción. Para documentar las construcciones, LISP permite la inserción de comentarios. El punto y coma (;) indica al interprete que todo lo que está a la derecha hasta el fin de la línea, es comentario. 5.1 DEFUN La plantilla general para DEFUN es la siguiente: (DEFUN < nombre del procedimiento> ; nombre de la función ( < parámetro 1> <parámetro 2> … <parámetro N) ; argumentos < forma 1 > ; cuerpo de la función: < forma 2 > ; varias formas. … < forma M > ) Como ejemplos, a continuación se definen un procedimiento para rotar a la izquierda y otro para rotar a la derecha los elementos de una lista dada como argumento: > (DEFUN rotizq (Lista) (APPEND (REST Lista) (LIST (FIRST Lista)))) ROTIZQ > (rotizq '(a b c d e)) (B C D E A) > (DEFUN rotder (Lista) (APPEND (LAST Lista) (BUTLAST Lista))) ROTDER > (rotder '(a b c d e)) (E A B C D) 5.2 LET Es una primitiva que liga parámetros de la misma manera que éstos son ligados al iniciar la ejecución de un procedimiento. La plantilla general de LET es la siguiente: ( LET ( (< parámetro 1> <valor inicial 1 ) … ( parámetro N> <valor inicial N ) ) < forma 1> … < forma M> ) A continuación, utilizando LET, se construye una operación que retorna una lista que tiene los objetos extremos de la lista original dada. > (SETF semana '(LUN MAR MIE JUE VIE SAB DOM)) (LUN MAR MIE JUE VIE SAB DOM) > (LET ((primero (FIRST semana)) (último (LAST semana))) (CONS primero último)) (LUN DOM) 10 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 17. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP Como se demuestra en el siguiente ejemplo, la primitiva LET evalúa en paralelo sus formas para valores iniciales, antes de que cualquiera de sus parámetros sea ligado. > (SETF a 'Valor-Externo) ; El valor de a es Valor-Externo VALOR-EXTERNO > (LET ((a 'Valor-Interno) ; El valor de a será Valor-Interno (b a)) ; El valor de b será Valor-Externo (LIST a b)) (VALOR-INTERNO VALOR-EXTERNO) > 5.3 LET* LET* es la versión de LET que evalúa en forma secuencial sus formas para valores iniciales. Esto es, liga los parámetros de tal forma que el valor de un parámetro ligado con anterioridad puede ser utilizado para calcular el valor de un parámetro ligado después. > (SETF a 'Valor-Externo) ; El valor de a es Valor-Externo VALOR-EXTERNO > (LET* ((a 'Valor-Interno) ; El valor de a será Valor-Interno (b a)) ; El valor de b será Valor-Interno (LIST a b)) (VALOR-INTERNO VALOR-INTERNO) 6. PREDICADOS Y CONDICIONALES Un predicado es un procedimiento que devuelve un valor que puede ser verdadero o falso. El resultado falso siempre se indica con NIL, mientras que el símbolo T o cualquier valor diferente de NIL se considera como verdadero. Estas pruebas, combinadas con condicionales permiten definir procedimientos mucho más poderosos. 6.1 =, EQ, EQL y EQUAL Existen varios predicados que determinan si sus argumentos son iguales. • El predicado = verifica que sus argumentos representen el mismo número, aun cuando no sean del mismo tipo numérico. • EQ verifica que sus argumentos estén representados en las misma localidades de memoria, es decir que sean símbolos idénticos. • EQL primero verifica si sus argumentos satisfacen EQ. Si no lo hacen trata de ver si son números del mismo tipo y con igual valor. • EQUAL primero verifica si sus argumentos satisfacen EQL. Si no lo hacen trata de verificar si son listas cuyos elementos satisfacen EQUAL. > (SETF X 4 Y 4.0 FELINO 'GATO AVE 'PATO DIAS '(LUN MAR MIE JUE VIE)) (LUN MAR MIE JUE VIE) > (= X Y) T > (EQ X Y) NIL > (EQ FELINO 'GATO) T > (EQ '(LUN MAR MIE JUE VIE) DIAS) NIL Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 11 > (EQL AVE 'PATO)
  • 18. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES T > (EQL '(LUN MAR MIE JUE VIE) DIAS) NIL > (EQUAL 'GATO FELINO) T > (EQUAL '(LUN MAR MIE JUE VIE) DIAS) T > (EQUAL X Y) NIL 6.2 MEMBER El predicado MEMBER verifica que su primer argumento sea un elemento del nivel superior de su segundo argumento, que debe ser una lista. Devuelve lo que queda de la lista al encontrar el símbolo coincidente, si éste pertenece a dicha lista. > (SETF ORACION '(La imaginación es más importante que el conocimiento) PAREJAS '((Luis Ana) (Rodrigo Martha) (Juan Rosa))) ((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA)) > (MEMBER 'importante ORACION) (IMPORTANTE QUE EL CONOCIMIENTO) > (MEMBER 'Rodrigo PAREJAS) NIL > (MEMBER '(Rodrigo Martha) PAREJAS) NIL MEMBER normalmente hace sus pruebas utilizando EQL, por este motivo, en el ejemplo anterior, no puede reconocer a la sublista (Rodrigo Martha) como miembro de PAREJAS. Pero COMMON LISP permite el uso de argumentos clave para modificar el comportamiento de ciertos procedimientos como MEMBER. La sintaxis para incluir argumentos clave en el predicado MEMBER, requiere de una palabra clave :TEST o :TEST-NOT, seguida por el argumento clave. El argumento clave está compuesto por los caracteres #’ y el nombre del procedimiento a ser utilizado, en este caso resultaría #’EQUAL. En particular, la palabra clave :TEST indica que el siguiente argumento especifica la prueba que debe usar MEMBER. Si en su lugar aparece la palabra clave :TEST-NOT, MEMBER devuelve lo que queda de la lista luego de la primera aparición de un elemento, si lo hay, que no sea igual al primer argumento, donde el argumento clave determina qué es lo que significa igual. El objetivo de los caracteres #’ es producir un procedimiento objeto a partir del nombre del procedimiento. Los cinco caracteres EQUAL constituyen el nombre del procedimiento. Las instrucciones de la computadora que ejecutan la prueba requerida constituyen el procedimiento objeto. De esta forma, el argumento clave resulta ser una variable cuyo valor es un procedimiento objeto, y como tal puede ser ligada a un símbolo. > (MEMBER 'Rodrigo PAREJAS :TEST #'EQUAL) NIL > (MEMBER 'Rodrigo PAREJAS :TEST-NOT #'EQUAL) ((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA)) > (SETF PRED #'EQUAL) ; Argumento clave es ligado a símbolo PRED #<function 2 #x8D2ADC> ; Respuesta del sistema > (MEMBER '(Rodrigo Martha) PAREJAS :TEST PRED) ((RODRIGO MARTHA) (JUAN ROSA)) 12 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 19. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP > (MEMBER '(Rodrigo Martha) PAREJAS :TEST-NOT PRED) ((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA)) > (MEMBER '(Luis Ana) PAREJAS :TEST PRED) ((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA)) > (MEMBER '(Luis Ana) PAREJAS :TEST-NOT PRED) ((RODRIGO MARTHA) (JUAN ROSA)) > (MEMBER '(Juan Rosa) PAREJAS :TEST PRED) ((JUAN ROSA)) > (MEMBER '(Juan Rosa) PAREJAS :TEST-NOT PRED) ((LUIS ANA) (RODRIGO MARTHA) (JUAN ROSA)) En programas antiguos, se pueden ver expresiones como (FUNCTION EQUAL), en lugar de #’EQUAL. La combinación #’ es un tipo de refinamiento sintáctico. En realidad, el intérprete LISP al encontrar la secuencia #’<expresión> la convierte en (FUNCTION <expresión>). Algunas versiones modernas de LISP todavía soportan la sintaxis antigua, por compatibilidad. > (MEMBER '(Rodrigo Martha) PAREJAS :TEST (FUNCTION EQUAL)) ((RODRIGO MARTHA) (JUAN ROSA)) > 6.3 ATOM, NUMBERP, SYMBOLP y LISTP LISP tiene varios predicados que verifican si un objeto pertenece a un tipo especial de datos. PREDICADO PRUEBA ATOM ¿Es un átomo? NUMBERP ¿Es un número? SYMBOLP ¿Es un símbolo? LISTP ¿Es una lista? > PI 3.14159265358979 > (ATOM PI) T > (NUMBERP PI) T > (SYMBOLP PI) NIL > (SYMBOLP 'PI) T > (LISTP PI) NIL > (LISTP 'PI) NIL En LISP existe una importante peculiaridad ya NIL y la lista vacía ( ) son totalmente equivalentes. Además, NIL y ( ) son tanto símbolos como listas. > NIL NIL > () NIL > (ATOM NIL) T > (ATOM ()) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 13
  • 20. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES T > (SYMBOLP NIL) T > (SYMBOLP ()) T > (LISTP NIL) T > (LISTP ()) T 6.4 NULL y ENDP Son predicados que verifican si su argumento es una lista vacía. Los siguientes ejemplos ilustran la diferencia entre los dos predicados. > (REST (LAST '(A B C D))) NIL > (NULL (REST (LAST '(A B C D)))) T > (ENDP (REST (LAST '(A B C D)))) T > (NULL PI) NIL > (ENDP PI) T > (NULL 'PI) NIL > (ENDP 'PI) T 6.5 ZEROP, PLUSP, MINUSP, EVENP, ODDP, > y < Además de NUMBERP, los predicados que trabajan con átomos numéricos, son los siguientes: PREDICADO PRUEBA ZEROP ¿Es cero? PLUSP ¿Es positivo? MINUSP ¿Es negativo? EVENP ¿Es número par? ODDP ¿Es número impar? > ¿Están en orden descendente? < ¿Están en orden ascendente? 6.6 AND, OR y NOT Para combinar los resultados de las pruebas de dos o más predicados, se pueden utilizar los operadores lógicos AND, OR y NOT. 14 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 21. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP OPERADOR OPERACIÓN AND • Los argumentos son evaluados de izquierda a derecha. Si alguno de ellos tiene como valor NIL, el resto de los argumentos ya no se evalúan y el valor devuelto es NIL. • Si todos los argumentos tienen un valor diferente de NIL, se devuelve el valor del último de los argumentos. OR • Los argumentos son evaluados de izquierda a derecha. Si alguno de ellos tiene valor diferente de NIL, ninguno de los argumentos se evalúan y el valor devuelto es ese valor diferente de NIL. • Si ninguno de los argumentos tiene un valor diferente de NIL, se devuelve el valor NIL. NOT • Convierte valores NIL a T y valores diferentes de NIL a NIL. > (SETF mascotas '(perro gato)) (PERRO GATO) > (AND (MEMBER 'perro mascotas) (MEMBER 'tigre mascotas)) NIL > (OR (MEMBER 'perro mascotas) (MEMBER 'tigre mascotas)) (PERRO GATO) > (AND (MEMBER 'perro mascotas) (NOT (MEMBER 'tigre mascotas))) T > (OR (MEMBER 'perro mascotas) (NOT (MEMBER 'tigre mascotas))) (PERRO GATO) > (OR (NOT (MEMBER 'perro mascotas)) (MEMBER 'tigre mascotas)) NIL 6.7 IF, WHEN y UNLESS Los predicados se utilizan casi siempre dentro de condicionales, para determinar de entre varias formas cuál debe evaluarse. LISP proporciona los siguientes condicionales básicos: (IF <prueba> <forma a evaluar si la prueba es no NIL> <forma a evaluar si la prueba es NIL>) (WHEN <prueba> <forma(s) a evaluar si la prueba es no NIL>) (UNLESS <prueba> <forma(s) a evaluar si la prueba es NIL>) Tanto WHEN como UNLESS, pueden tener cualquier número de argumentos. El primero siempre es la forma de prueba; el último proporciona el valor que se devolverá. Sus argumentos, después del primero, sólo se evalúan si el valor de la prueba así lo indica. 6.8 COND Es un condicional mucho más versátil que IF, WHEN y UNLESS. La plantilla de esta forma es la siguiente: (COND (<prueba 1> <consecuente 1-1> <consecuente 1-2> … <consecuente 1-N>) (<prueba 2> <consecuente 2-1> <consecuente 2-2> … <consecuente 2-N>) … (<prueba M> <consecuente M-1> <consecuente M-2> … <consecuente M-N>)) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 15
  • 22. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES Cada cláusula contiene una prueba y cero o más formas adicionales denominadas consecuentes. Se evalúan en secuencia las formas de prueba de cada cláusula hasta que se encuentre una cuyo valor sea diferente de NIL. En este caso se dice que la cláusula correspondiente se activa y se evalúan sus formas consecuentes. El valor que retorna COND, es el de la última forma consecuente de la cláusula activada. Si el valor de todas las formas de prueba es NIL, el valor que retorna COND, también es NIL. Si una cláusula con una forma de prueba diferente de NIL no tiene formas consecuentes, entonces el valor retornado por COND es el valor de la forma de prueba. > (DEFUN sol-ecuación-cuad (a b c) (SETF delta (- (* b b) (* 4 a c))) (COND ((PLUSP delta) (LET ((f1 (- (/ b (* 2 a)))) (f2 (/ (SQRT delta) (* 2 a)))) (LIST 'X1 '= (+ f1 f2) 'X2 '= (- f1 f2)))) ((MINUSP delta) (LIST 'No 'hay 'solución 'real!)) (T (LIST 'X1 '= 'X2 '= (- (/ b (* 2 a))))))) SOL-ECUACIóN-CUAD > (sol-ecuación-cuad 1 -1 20) (NO HAY SOLUCIóN REAL!) > (sol-ecuación-cuad 1 -1 -20) (X1 = 5.0 X2 = -4.0) > (sol-ecuación-cuad 1 -10 25) (X1 = X2 = 5) 6.9 CASE CASE evalúa la forma clave y la compara con todas las claves sin evaluar, usando EQL. Si la clave se encuentra, la cláusula correspondiente se activa y todas las formas consecuentes se evalúan. Su plantilla es la siguiente: (CASE <forma clave> (<clave 1> <consecuente 1-1> <consecuente 1-2> … <consecuente 1-N>) (<clave 2> <consecuente 2-1> <consecuente 2-2> … <consecuente 2-N>) (<clave M> <consecuente M-1> <consecuente M-2> … <consecuente M-N>)) • Si ninguna de las cláusulas se activa, CASE retorna NIL. • Si la clave en la última cláusula es T u OTHERWISE, y ninguna de las otras cláusulas se activa, se activa la última. • Si la clave es una lista en lugar de un átomo, CASE evalúa la forma clave y usa MEMBER para buscarla en la lista de claves sin evaluar. Si la clave se encuentra, la cláusula correspondiente se activa y todas las formas consecuentes se evalúan. > (DEFUN área (figura radio) (CASE figura (círculo (* pi radio radio)) (esfera (* 4 pi radio radio)) (OTHERWISE 'No-es-círculo-o-esfera))) áREA > (área 'círculo 3) 28.2743338823081 > (área 'esfera 4) 201.061929829747 > (área 'triángulo 5) NO-ES-CíRCULO-O-ESFERA 16 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 23. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP 7. ABSTRACCIÓN DE PROCEDIMIENTOS Y RECURSIÓN La abstracción de procedimientos es un proceso que ayuda a construir programas grandes y complicados sobre la base de una combinación de funciones o procedimientos más simples. La abstracción de procedimientos ayuda a pensar en un nivel superior, al permitir obviar los detalles de cómo se hacen las cosas en un nivel inferior. Se puede programar de arriba hacia abajo, trabajando primero en los procedimientos de nivel superior, posponiendo los de nivel inferior. La abstracción de procedimientos ayuda a mantener las definiciones breves y comprensibles. Un caso especial e importante de la abstracción de procedimientos es aquel en el cual la abstracción sobre la que se construye un procedimiento es el mismo procedimiento. 7.1 PROCEDIMIENTOS RECURSIVOS Cuando un procedimiento se llama a sí mismo, se dice que hace una llamada recursiva. A las definiciones que describen un procedimiento parcialmente en términos de llamadas recursivas se las denomina definiciones recursivas. Suponiendo que no se tiene la función primitiva MEMBER, definamos como un procedimiento recursivo sencillo la función MBR. Dado un átomo y una lista como argumentos, se tiene la siguiente descripción para la función MBR: 1. Si la lista es nula, el átomo no es un miembro de la lista, retornar NIL. 2. Si el átomo es igual al primer elemento de la lista, entonces el átomo es miembro de la lista, retornar T. 3. Si el átomo no es igual al primer elemento de la lista, entonces el átomo es miembro de la lista si y sólo si es un miembro del resto de la lista. Las dos primeras consideraciones son relativamente sencillas de entender. La tercera es un poco más sutil y puede ser interpretada como una llamada recursiva a MBR, dándole como argumentos el átomo y el resto de la lista original. Esto, traducido a LISP, resulta: > (DEFUN MBR (átomo lista) (COND ((ENDP lista) NIL) ((EQL átomo (FIRST lista)) T) (T (MBR átomo (REST lista))))) MBR > (MBR 'a '(a b c d)) T > (MBR 'b '(a b c d)) T > (MBR 'd '(a b c d)) T > (MBR 'b '()) NIL Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 17
  • 24. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES Utilizando similares técnicas, definamos ahora la función EQLIST que retorna T si las dos listas de átomos dadas como argumentos son iguales. La descripción para esta función es como sigue: Definir EQLIST con argumentos lista1 y lista2: • Si la lista1 es vacía, retornar el resultado de comprobar si lista2 es vacía. • Si la lista2 es vacía, retornar NIL. • Si el primer elemento de lista1 y el primer elemento de lista2 no son iguales, retornar NIL. • Si no, realizar una llamada recursiva a EQLIST dando como arguentos el resto de lista1 y el resto de lista2. > (DEFUN EQLIST (lista1 lista2) (COND ((ENDP lista1) (ENDP lista2)) ((ENDP lista2) NIL) ((NOT (EQL (FIRST lista1) (FIRST lista2))) NIL) (T (EQLIST (REST lista1) (REST lista2))))) EQLIST > (EQLIST () '(A B C)) NIL > (EQLIST '(A B C) ()) NIL > (EQLIST () ()) T > (EQLIST '(A B C) '(A B C)) T > (EQLIST '(A B C) '(B C A)) NIL Ahora definamos una versión de la función llamada ELIMINAR, la misma que acepta dos argumentos: un átomo y una lista. El resultado es una lista en la que la ocurrencia de átomo ha sido eliminada de la lista original dada. La descripción es la siguiente: Definir ELIMINAR con átomo y lista como argumentos: 1. Si la lista es vacía, retornar NIL 2. Si el átomo es igual al primer elemento de la lista, retornar el resto de la lista. 3. Si no, construir una lista con el primer elemento de la lista y lo que retorne la llamada recursiva a ELIMINAR con los argumentos átomo y resto de la lista. > (SETF animales '(oso perro gato toro perro loro oso)) (OSO PERRO GATO TORO PERRO LORO OSO) > (DEFUN ELIMINAR (átomo lista) (COND ((ENDP lista) NIL) ((EQL átomo (FIRST lista)) (REST lista)) ((CONS (FIRST lista) (ELIMINAR átomo (REST lista)))))) ELIMINAR > (ELIMINAR ‘perro animales) (OSO GATO TORO PERRO LORO OSO) > (ELIMINAR 'oso animales) (PERRO GATO TORO PERRO LORO OSO) 18 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 25. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP Como se puede ver de los resultados, sólo la primera ocurrencia de átomo es eliminada de la lista. Realizando una modificación al procedimiento anterior, se define la función ELIMINAR-TODO, capaz de eliminar todas la ocurrencias de átomo en la lista: Definir ELIMINAR-TODO con átomo y lista como argumentos: 1. Si la lista es vacía, retornar NIL 2. Si el átomo es igual al primer elemento de la lista, llamar recursivamente a ELIMINAR- TODO dándole como argumentos el átomo y el resto de la lista. 3. Si no, construir una lista con el primer elemento de la lista y lo que retorne la llamada recursiva a ELIMINAR-TODO con los argumentos átomo y resto de la lista. > (DEFUN ELIMINAR-TODO (átomo lista) (COND ((ENDP lista) NIL) ((EQL átomo (FIRST lista)) (ELIMINAR-TODO átomo (REST lista))) ((CONS (FIRST lista) (ELIMINAR-TODO átomo (REST lista)))))) ELIMINAR-TODO > (ELIMINAR-TODO 'perro animales) (OSO GATO TORO LORO OSO) > (ELIMINAR-TODO 'oso animales) (PERRO GATO TORO PERRO LORO) Como se vio anteriormente, la función primitiva REVERSE invierte todos los elementos del nivel superior de una lista dada como argumento. La siguiente función denominada INVERTIR, es una generalización de REVERSE, ya que invierte todos los elementos de una lista, sean estos átomos o listas. > (DEFUN INVERTIR (lista) (COND ((ENDP lista) NIL) ((LISTP (FIRST (LAST lista))) (CONS (INVERTIR (FIRST (LAST lista))) (INVERTIR (BUTLAST lista)))) (T (CONS (FIRST (LAST lista)) (INVERTIR (BUTLAST lista)))))) INVERTIR > (SETF lista1 '(a b c d e f)) (A B C D E F) > (SETF lista2 '((a b) (c d) e (f g))) ((A B) (C D) E (F G)) > (REVERSE lista1) (F E D C B A) > (INVERTIR lista1) (F E D C B A) > (REVERSE lista2) ((F G) E (C D) (A B)) > (INVERTIR lista2) ((G F) E (D C) (B A)) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 19
  • 26. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES 7.2 PARÁMETROS OPCIONALES Los procedimientos hasta ahora definidos, han requerido de un argumento por cada parámetro. Pero LISP también permite definir procedimientos con parámetros opcionales, indicados con &OPTIONAL, para los cuales puede haber o no argumentos correspondientes. > (DEFUN raíz (x &optional n) (IF n (expt x (/ 1 n)) (sqrt x))) RAíZ > (raíz 9) ; llamada a raíz con un argumento, n se liga a NIL y se usa SQRT. 3.0 > (raíz 27 3) : llamada a raíz con 2 argumentos, n se liga a 3 y se usa EXPT. 3.0 Todos los parámetros opcionales que no tengan argumento correspondiente, se ligan al valor NIL por omisión. Pero también se puede especificar el valor por omisión al que se deben ligar los parámetros opcionales. > (DEFUN raíz (x &optional (n 2)) (expt x (/ 1 n))) RAíZ > (raíz 16) ; llamada a raíz con un argumento, n se liga a 2. 4.0 > (raíz 64 3) ; llamada a raíz con 2 argumentos, n se liga a 3. 4.0 Los parámetros opcionales casi siempre simplifican los programas, al reducir la necesidad de procedimientos auxiliares. > (DEFUN cuenta-elementos (lista &optional (resultado 0)) (IF (ENDP lista) resultado (cuenta-elementos (REST lista) (+ 1 resultado)))) CUENTA-ELEMENTOS > (cuenta-elementos '(La imaginación es más importante que el conocimiento)) 8 La llamada a cuenta-elementos con un sólo argumento hace que el valor inicial de resultado sea cero. Pero el mismo procedimiento es usado con dos argumentos en las llamadas recursivas. En este caso el valor por omisión de resultado se ignora en favor del valor del argumento proporcionado. 7.3 PARÁMETROS RESTANTES Un parámetro restante, indicado por &REST se liga a una lista de todos los valores de los argumentos que de otra manera no tendrían un parámetro correspondiente. > (DEFUN potencia (x &REST exponentes) (POTEXP x exponentes)) POTENCIA > (DEFUN potexp (resultado exponentes) (IF (ENDP exponentes) resultado (potexp (EXPT resultado (FIRST exponentes)) (REST exponentes)))) POTEXP > (potencia 3) 20 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 27. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP 3 > (potencia 3 2) 9 > (potencia 3 2 4) 6561 7.4 PARÁMETROS CLAVE Un parámetro clave se usa en situaciones en las que hay varios parámetros, muchos de los cuales casi siempre se ligan a valores por omisión. En tales situaciones si se usaran parámetros opcionales, sería muy difícil recordar el orden de ellos, con su respectivo valor inicial. Cuando se define procedimientos con parámetros clave, estos se indican con &KEY. > (DEFUN rota-lista-der (lista n-puestos) (IF (ZEROP n-puestos) lista (rota-lista-der (APPEND (LAST lista) (BUTLAST lista)) (- n-puestos 1)))) ROTA-LISTA-DER > (DEFUN rota-lista-izq (lista n-puestos) (IF (ZEROP n-puestos) lista (rota-lista-izq (APPEND (REST lista) (LIST (FIRST lista))) (- n-puestos 1)))) ROTA-LISTA-IZQ > (DEFUN rota-lista (lista &KEY dirección (lugares 1)) (IF (EQ dirección 'izquierda) (rota-lista-izq lista lugares) (rota-lista-der lista lugares))) ROTA-LISTA > (rota-lista '(a b c d e) :dirección 'izquierda :lugares 3) (D E A B C) > (rota-lista '(a b c d e) :dirección 'derecha :lugares 3) (C D E A B) En el procedimiento ROTA-LISTA definido anteriormente, dirección y lugares, aparecen como parámetros clave. En la llamada a la función, las palabras clave :dirección y :lugares, indican la presencia de argumentos que deben ser asignados a los parámetros dirección y lugares. Las ligaduras son determinadas por las palabras clave, no por el orden de aparición en la llamada. Esto se demuestra en los siguientes ejemplos. > (rota-lista '(a b c d e) :lugares 4 :dirección 'izquierda) (E A B C D) > (rota-lista '(a b c d e) :lugares 2 :dirección 'derecha) (D E A B C) 7.5 PARÁMETROS AUXILIARES Un parámetro auxiliar, indicado por &AUX, no corresponde a ningún argumento. Los parámetros auxiliares en realidad son formas LET* disfrazadas. > (DEFUN extremos (lista &AUX (primero (FIRST lista)) (último (LAST lista))) (CONS primero último)) EXTREMOS > (extremos '(a b c d e)) (A E) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 21
  • 28. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES 8. TRANSFORMACIONES Y FUNCIONES ANÓNIMAS Los procedimientos recursivos, permiten transformar y filtrar. Cuando se transforma una lista, la longitud de la lista transformada es la misma que la longitud de la lista original. Cuando se filtra una lista la longitud de la lista de salida es menor, a menos que todos los elementos de la lista original pasen la prueba del filtro. 8.1 MAPCAR Es una primitiva que facilita el procedimiento de transformación de listas. MAPCAR requiere del nombre de un procedimiento de transformación junto con la lista de los elementos que serán transformados. En el siguiente ejemplo MAPCAR se utiliza para comprobar los números que son impares, utilizando la primitiva ODDP. La secuencia #’, tal como se explico anteriormente, produce un procedimiento objeto, a partir de un nombre de procedimiento. Cuando se evalúa una forma MAPCAR, LISP suministra cada elemento de su segundo argumento al procedimiento de transformación especificado por su primer argumento. El valor devuelto es una lista de resultados. > (mapcar #'oddp '(1 2 3)) (T NIL T) El procedimiento usado por MAPCAR no está restringido a ser un procedimiento de un parámetro; si el procedimiento tiene más de un parámetro debe haber un número correspondiente de listas de las cuales extraer argumentos. En el siguiente ejemplo MAPCAR toma un elemento de cada lista de argumentos y los ensambla para un procedimiento de transformación. > (mapcar #'= '(1 2 3) '(3 2 1)) (NIL T NIL) 8.2 REMOVE-IF y REMOVE-IF-NOT Son primitivas que permiten filtrar listas. REMOVE-IF elimina todos los elementos que satisfacen el predicado dado. REMOVE-IF-NOT, en cambio elimina todos los elementos que no lo satisfacen. > (SETF digitos '(0 1 2 3 4 5 6 7 8 9)) (0 1 2 3 4 5 6 7 ...) > (REMOVE-IF #'EVENP digitos) (1 3 5 7 9) > (REMOVE-IF-NOT #'EVENP digitos) (0 2 4 6 8) 8.3 COUNT-IF y FIND-IF COUNT-IF cuenta los elementos de una lista, que satisfacen una determinada prueba. > (COUNT-IF #'EVENP digitos) 5 > (COUNT-IF-NOT #'ZEROP digitos) 9 22 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 29. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP FIND-IF encuentra el primer elemento de una lista, que satisface una determinada prueba. > (FIND-IF #'EVENP digitos) 0 > (FIND-IF #'ODDP digitos) 1 8.4 FUNCALL y APPLY Aplica el valor de su primer argumento al valor de los otros argumentos. Usa tantos argumentos como requiera el procedimiento mencionado, más uno para el nombre del procedimiento. FUNCALL permite definir procedimientos que tengan procedimientos como argumentos. > (FUNCALL #'FIRST '(A B C D)) ; Equivale a: (FIRST '(A B C D)) A > (FUNCALL #'+ '(1 2 3 4 5)) (1 2 3 4 5) > (FUNCALL #'+ 1 2 3 4 5) 15 APPLY suele tener dos argumentos. Usa el valor de su primer argumento sobre los elementos del valor de su segundo argumento, el cual debe ser una lista. La lista tiene tantos elementos como requiera el procedimiento mencionado. > (APPLY #'FIRST '((A B C D))) A > (APPLY #'+ '(1 2 3 4 5)) 15 En los casos en que APPLY aparezca con más de dos argumentos, todos los argumentos excepto el primero y el último se combinan en una lista, a la cual se añade el último argumento. > (APPLY #'+ 1 2 3 '(4 5)) ; La lista de argumentos dados a + es 15 ; (APPEND (LIST 1 2 3) '(4 5)) 8.5 FUNCIONES ANÓNIMAS (LAMBDA) Para los casos en que las funciones definidas por el usuario son utilizadas una sola vez, es preferible definir funciones anónimas. Las funciones anónimas son como las otras funciones del LISP, excepto que no tienen asignado un nombre y se las usa una vez. Las funciones anónimas son definidas mediante la expresión LAMBDA. > (SETF colores '(azul verde rojo )) (AZUL VERDE ROJO) > ((LAMBDA (lista) (FIRST (REST lista))) colores) VERDE > (SETF aves '(gallo paloma pavo)) felinos '(león tigre pantera) mascotas '(perro gato loro) (PERRO GATO LORO) > (SETF animales (LIST aves felinos mascotas)) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 23 ((GALLO PALOMA PAVO) (LEóN TIGRE PANTERA) (PERRO GATO LORO))
  • 30. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES > (MAPCAR #'(LAMBDA (lista) (FIRST (REST lista))) animales) (PALOMA TIGRE GATO) 9. ITERACIÓN Al igual que la recursión, la iteración es una estrategia general para controlar la evolución de los cálculos. La iteración puede realizarse con varias primitivas que proporciona LISP. 9.1 DOTIMES Permite escribir procedimientos sencillos con iteración controlada por un contador. La plantilla general es la siguiente: (DOTIMES (<parámetro de cuenta> <forma límite superior> <forma resultado>) <cuerpo>) Cuando empieza la ejecución de DOTIMES, la forma límite superior se evalúa produciendo un número n. Entonces los números desde 0 hasta n-1 se asignan, uno después de otro, al parámetro de cuenta. Para cada valor, se ejecuta el cuerpo. A la salida, la ligadura del parámetro de cuenta se elimina y la forma resultado se evalúa, produciendo el valor de la forma DOTIMES. Si DOTIMES no tiene forma resultado, devuelve NIL. > (DEFUN FACTORIAL (num) (LET ((resultado 1)) (DOTIMES (cuenta num resultado) (SETF resultado (* (+ 1 cuenta) resultado))))) FACTORIAL > (FACTORIAL 0) 1 > (FACTORIAL 1) 1 > (FACTORIAL 5) 120 9.2 DOLIST La primitiva DOLIST es similar a DOTIMES excepto que los parámetros de una forma lista se asignan al parámetro de cuenta uno después del otro. La plantilla es la siguiente: (DOLIST (<parámetro de cuenta> <forma lista> <forma resultado>) <cuerpo>) Para ilustrar el uso de DOLIST, a continuación se define la función REVERSE-DOLIST: > (DEFUN REVERSE-DOLIST (lista) (LET ((resultado NIL)) (DOLIST (cont lista resultado) (SETF resultado (CONS cont resultado))))) REVERSE-DOLIST > (REVERSE lista1) (F E D C B A) > (REVERSE-DOLIST lista1) (F E D C B A) 24 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 31. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP 9.3 DO y DO* La primitiva DO puede utilizarse para hacer iteraciones cuando DOTIMES y DOLIST no son lo suficientemente flexibles. La plantilla de DO es la siguiente: (DO ((<parámetro 1> <valor inicial 1> <forma de actualización 1>) (<parámetro 2> <valor inicial 2> <forma de actualización 2>) … (<parámetro N> <valor inicial N> <forma de actualización N>)) (<prueba para finalizar> <formas intermedias, si existen> <forma resultado>) <cuerpo>) Los detalles de la operación de la primitiva DO, son los siguientes: • La primera parte de una forma DO siempre es una lista de parámetros que se ligarán a valores iniciales, al entrar al DO. Si no hay parámetros la lista vacía debe aparecer en la primera posición. Las especificaciones para parámetros pueden incluir formas de actualización, además de los nombres de variables y formas para valor inicial. Todas la formas valor inicial se evalúan antes de ligarlas a los parámetros. De manera similar, todas las formas de actualización se evalúan antes de hacer las nuevas asignaciones. Por consiguiente se dice que DO maneja sus parámetros en paralelo. En este aspecto DO es similar a LET, lo cual llega a ser crítico cuando un parámetro DO aparece en una forma de inicialización o de actualización. • La segunda parte de un DO establece cuándo termina el ciclo y qué valor se debe devolver. Esta parte consta de una lista cuya forma inicial es una prueba para terminación. Las formas que siguen en esta lista son evaluadas en orden cuando el valor de la forma de prueba es diferente de NIL. El valor devuelto por DO es el valor de la última forma en esta lista. Antes de cada pasada a través del cuerpo, se evalúa la prueba, incluyendo la primera vez. Si sólo hay una forma, ésta es la prueba y DO devuelve NIL. • La tercera parte de una forma DO, el cuerpo, consta de formas que son evaluadas secuencialmente. Todos los valores se ignoran, es decir las evaluaciones sólo se hacen por su posibles efectos secundarios. Siempre que dentro del cuerpo de un DO se encuentre una expresión que inicie con RETURN, el DO termina inmediatamente. El valor retornado es el indicado por la expresión RETURN. La primitiva DO* es similar a DO, excepto que hace la ligadura secuencial de valores, en lugar de hacerlo en paralelo. DO* es a DO, lo que LET es a LET*. > (DEFUN REVERSE-DO (lista) (DO ((list lista (REST list)) (resultado NIL (CONS (FIRST list) resultado))) ((ENDP list) resultado))) REVERSE-DO > (REVERSE lista1) (F E D C B A) > (REVERSE-DO lista1) (F E D C B A) 9.4 LOOP La primitiva LOOP, también se usa para iteración, pero a diferencia de las otras formas, sólo tiene un cuerpo. Las formas del cuerpo son evaluadas una y otra vez. Cuando se encuentra con una forma (RETURN <expresión>), la expresión es evaluada y LOOP termina retornando el valor de la expresión. Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 25
  • 32. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES 9.5 PROG1 y PROGN Las primitivas PROG1 y PROGN se utilizan para combinar explícitamente formas en secuencia. (PROG1 <forma de respuesta> <forma secundaria 1> … <forma secundaria N>) (PROGN <forma secundaria 1> <forma secundaria 2> … <forma de respuesta>) PROG1 establece como valor de respuesta para la forma completa la primera, mientras que PROGN devuelve el resultado de la evaluación de la última. La siguiente función calcula el promedio de una lista de números dada como argumento y utiliza las formas LOOP y PROGN. > (DEFUN promedio (lista) (IF (ENDP lista) 0 (LET* ((total (FIRST lista)) (cuenta 1)) (LOOP (SETF lista (REST lista)) (IF (ENDP lista) (RETURN (/ total cuenta)) (PROGN (SETF total (+ total (FIRST lista))) (SETF cuenta (+ cuenta 1)))))))) PROMEDIO > (promedio '()) 0 > (promedio '(3 5 7 9 11)) 7 10. LECTURA Y ESCRITURA Para establecer la comunicación entre los procedimientos y el usuario, LISP proporciona varias primitivas tanto para proporcionar como para obtener información. 10.1 PRINT, PRIN1, PRINC y TERPRI La primitiva PRINT evalúa su argumento y lo imprime en una nueva línea, seguido por un espacio en blanco. El valor devuelto por PRINT es el valor de su argumento. Ejemplos: > (SETF paciente '((nombre Andrade) (síntomas (fiebre comezón náusea)))) ((NOMBRE ANDRADE) (SíNTOMAS (FIEBRE COMEZóN NáUSEA))) > (PRINT paciente) ((NOMBRE ANDRADE) (SíNTOMAS (FIEBRE COMEZóN NáUSEA))) ; Acción de PRINT ((NOMBRE ANDRADE) (SíNTOMAS (FIEBRE COMEZóN NáUSEA))) ; Valor retornado por PRINT > (DEFUN reporte (paciente) (PROGN (PRINT (LIST 'Paciente (SECOND (ASSOC 'nombre paciente)) 'presenta (LENGTH (SECOND (ASSOC 'síntomas paciente))) 'síntomas (SECOND (ASSOC 'síntomas paciente)))) NIL)) REPORTE > (reporte paciente) (PACIENTE ANDRADE PRESENTA 3 SíNTOMAS (FIEBRE COMEZóN NáUSEA)) ; Acción de PRINT NIL ; Valor retornado por PROGN PRINT puede imprimir también cadenas, otro de los tipos de datos de LISP. Las cadenas son secuencias de caracteres limitadas por comillas al inicio y al final. 26 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 33. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP > (PRINT "Hola que tal!") "Hola que tal!" ; Acción de PRINT "Hola que tal!" ; Valor retornado por PRINT Hay otras primitivas derivadas de PRINT que están disponibles para asistir en las labores de presentación de mensajes al usuario: • PRIN1 es igual a PRINT, excepto que no imprime en una línea nueva, ni pone un espacio al final de la línea. • PRINC imprime la cadena dada como argumento sin incluír las comillas, ni retorno ni espacio en blanco al final. • TERPRI no requiere de argumentos y su efecto es forzar un cambio de línea. El siguiente ejemplo ilustra el efecto de estas primitivas: > (DEFUN media4 (uno dos tres cuatro) (PRINT "El promedio de:") (TERPRI) (PRIN1 uno) (PRINC " ") (PRIN1 dos) (PRINC " ") (PRIN1 tres) (PRINC " ") (PRIN1 cuatro) (TERPRI) (PRINC "Da como resultado:") (/ (+ uno dos tres cuatro) 4)) MEDIA4 > (MEDIA4 3 5 7 9) "El promedio de:" 3 5 7 9 Da como resultado: 6 10.2 READ LISP se detiene cuando encuentra la primitiva READ, espera que se digite en el teclado una expresión. READ no imprime ningún mensaje, por lo que necesario utilizar una forma PRINT, para poner un mensaje al usuario indicando el tipo de respuesta que se espera. > (PROGN (SETF nombre NIL) (PRINT "Ingresar un nombre:") (SETF nombre (READ)) (PRINT (APPEND '(El nombre es) (LIST nombre))) NIL) "Ingresar un nombre:" Marcelo (EL NOMBRE ES MARCELO) NIL 10.3 FORMAT La primitiva FORMAT permite imprimir mensajes más elegantes, nítidos y similares a oraciones; conteniendo letras mayúsculas, minúsculas, y signos de puntuación. > (FORMAT T "Hola que tal!")Hola que tal! ;Impresión de FORMAT NIL ;El valor de FORMAT es NIL Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 27
  • 34. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES La letra T indica a FORMAT que imprima en el terminal. Para imprimir la cadena de caracteres en una nueva línea, se utiliza la directiva %. El signo ~ introduce una directiva. La directiva & también le dice a FORMAT que empiece en una nueva línea, pero no lo hace si ya hay una nueva línea. > (PROGN (FORMAT T "~%Hola que tal!~%") (FORMAT T "~%Esta línea se escribió luego de 1 línea en blanco. ~%") (FORMAT T "~&Pero esta línea está precedida por la directiva &.")) Hola que tal! Esta línea se escribió luego de 1 línea en blanco. Pero esta línea está precedida por la directiva &. NIL La directiva A, indica a FORMAT que debe insertar el valor del argumento adicional que aparece después de la cadena de caracteres de FORMAT. > (LET ((nombre NIL)) (FORMAT T "~%Ingresar un nombre: ") (SETF nombre (READ)) (FORMAT T "~%El nombre ingresado fue: ~A." nombre)) Ingresar un nombre: Roberto El nombre ingresado fue: ROBERTO. NIL 10.4 WITH-OPEN-FILE Esta primitiva crea flujos, liga variables a ellos y se conecta a archivos. Conceptualmente, los flujos son objetos LISP que sirven como fuentes o suministros de datos. Los flujos pueden conectarse a archivos en uno de sus extremos. Los flujos conectados a archivos que proporcionan datos se llaman flujos de entrada. Los flujos de entrada están involucrados con las formas READ. Los flujos conectados a archivos que reciben datos se llaman flujos de salida. Estos flujos están involucrados con las formas PRINT y FORMAT. La plantilla para WITH-OPEN-FILE permite la especificación de tres cosas: el nombre de la variable que se va a ligar al flujo, el nombre del archivo al cual se va a conectar el flujo; y la indicación si el flujo es de entrada o de salida. (WITH-OPEN-FILE (<nombre del flujo> <especificación del archivo> :direction :input) … (READ <nombre del flujo> ‘eof) ; leer datos del flujo de entrada, hasta el final del archivo (eof) …) (WITH-OPEN-FILE (<nombre del flujo> <especificación del archivo> :direction :output) … (PRINT <expresión para imprimir> <nombre del flujo>) …) 28 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 35. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP 10.5 ELT Es un acrónimo de ELemenTo. Se desempeña tanto con listas, como con cadenas. Recibe dos argumentos: • Si el primer argumento es una lista, devuelve el elemento especificado por su segundo argumento. • Si el primer argumento es una cadena, devuelve el carácter especificado por su segundo argumento. El primer elemento se especifica con el número cero (0). > (ELT '(a b c) 0) A > (ELT '(a b c) 2) C > (ELT "abc" 0) #a > (ELT "abc" 2) #c Las primitivas LENGTH y REVERSE, también pueden operar con cadenas lo mismo que con listas. > (LENGTH "Politécnica Nacional") 20 > (REVERSE "Politécnica Nacional") "lanoicaN acincétiloP" 10.6 STRING= y STRING-EQUAL Estas primitivas se utilizan para determinar si dos cadenas son iguales. STRING= detecta la diferencia entre mayúsculas y minúsculas, STRING-EQUAL no. > (STRING= "abc" "xyz") NIL > (STRING= "abc" "abc") T > (STRING= "abc" "ABC") NIL > (STRING-EQUAL "abc" "xyz") NIL > (STRING-EQUAL "abc" "abc") T > (STRING-EQUAL "abc" "ABC") T 10.7 CHAR= y CHAR-EQUAL Estas primitivas permiten determinar si dos caracteres son iguales. CHAR= detecta la diferencia entre mayúsculas y minúsculas; CHAR-EQUAL, no. > (CHAR= #a #b) NIL > (CHAR= #a #a) Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 29
  • 36. PROGRAMACIÓN EN LISP SISTEMAS INTELIGENTES T > (CHAR= #a #A) NIL > (CHAR-EQUAL #a #b) NIL > (CHAR-EQUAL #a #a) T > (CHAR-EQUAL #a #A) T 10.8 SEARCH Se utiliza para determinar si una cadena está contenida en otra. Si el primer argumento de SEARCH está contenido en el segundo, el resultado es la posición donde empieza la correspondencia. De otra forma SEARCH devuelve NIL. > (SEARCH "razones" "Corazones no entienden razones") 2 > (SEARCH "tienden" "Corazones no entienden razones") 15 > (SEARCH "corazones" "Corazones no entienden razones") NIL > (SEARCH "corazones" "Corazones no entienden razones" :TEST #'CHAR-EQUAL) 0 Al igual que LENGTH, REVERSE y ELT, SEARCH es también una primitiva que opera tanto con listas como con cadenas. > (SEARCH '(razones) '(Corazones no entienden razones)) 3 > (SEARCH '(tienden) '(Corazones no entienden razones)) NIL > (SEARCH '(corazones) '(Corazones no entienden razones)) 0 10.9 READ-CHAR Lee un sólo carácter, ya sea del terminal o de un archivo. > (READ-CHAR)H #H > (READ-CHAR)m #m 10.10 READ-LINE Lee una cadena de caracteres hasta cuando aparece el carácter de cambio de línea (<ENTER>) o el carácter de final de archivo (EOF). Retorna dos valores: La línea de caracteres leídos y el valor T. > (READ-LINE)Mientras leía esta línea de pronto me encontré con el final "Mientras leía esta línea de pronto me encontré con el final" T 30 Junio, 2003 Hugo A. Banda Gamboa, PhD, MSc.
  • 37. SISTEMAS INTELIGENTES PROGRAMACIÓN EN LISP A continuación se definen dos procedimientos, para ilustrar el uso de las formas de entrada y salida: LEER-TEXTO y BUSCAR-TEXTO. Para probar estas funciones, se supone que en el directorio de trabajo del LISP, existe un archivo de texto llamado “buscatxt.txt”. > (DEFUN leer-texto (archivo) (WITH-OPEN-FILE (datos archivo :direction :input) (DO ((línea (READ-LINE datos NIL) (READ-LINE datos NIL))) ((NOT línea) T) (FORMAT T "~% ~A" línea)))) LEER-TEXTO > (leer-texto "buscatxt.txt") BUSCAR-TEXTO es un procedimiento que busca a través de tal archivo una línea que contenga una subcadena en particular, después de lo cual imprime la línea completa. WITH-OPEN-FILE construye el flujo apropiado y READ-LINE lee el archivo línea por línea. SEARCH prueba cada línea hasta encontrar una que corresponda con el texto dado, hecho lo cual, FORMAT imprime la línea. T > (DEFUN buscar-texto (texto archivo) (WITH-OPEN-FILE (datos archivo :direction :input) (DO ((línea (READ-LINE datos NIL) (READ-LINE datos NIL))) ((NOT línea) (FORMAT T "~%No hay tal texto en: ~A" archivo)) (WHEN (SEARCH texto línea :TEST #'CHAR-EQUAL) (FORMAT T "~% ~A" línea) (RETURN T))))) BUSCAR-TEXTO > (BUSCAR-TEXTO "WITH-OPEN-FILE" "buscatxt.txt") línea completa. WITH-OPEN-FILE construye el flujo apropiado y READ-LINE lee T 11. BIBLIOGRAFÍA [1] Bahrami A. Designing Artificial Intelligence Based Software. Sigma Press, Wilmslow, UK, 1988. [2] Franz Inc. Allegro CL for Windows Volume 1: Getting Started, Ver 3.0. Franz Inc., USA, 1995. [3] Graham P. ANSI Common Lisp. Prentice Hall, USA, 1996. [4] Hekmatpour S. Introduction to LISP and Symbol Manipulation. Prentice Hall, UK, 1988. [5] Winstanley G. Program Design for Knowledge Based Systems. Sigma Press, Wilmslow, UK, 1987. [6] Winston P H, Horn B K P. LISP, 3ra. Edición. Addison-Wesley Iberoamericana, USA, 1991. Hugo A. Banda Gamboa, PhD, MSc. Junio, 2003 31