Está en la página 1de 69

Common Lisp

Programacin III

Apuntes de COMMON LISP para la asignatura Programacin III

Lic. Ricardo Monzn Prof. Adjunto Programacin III Facultad de Ciencias Exactas y Naturales y Agrimensura UNNE

Apuntes INDICE TEMA 1. SIMBOLOS, ATOMOS Y CONSES


1.1. SIMBOLOS LISP Y OBJETOS SIMBOLICOS 1.2. TIPOS ATOM: NUMEROS, CARACTERES Y STRINGS 1.3. TIPOS CONS 1.4. EVALUACIN EN LISP 1 2 4 8

TEMA 2. FUNCIONES PREDEFINIDAS SOBRE LISTAS


2.1. EXPRESIONES SIMBOLICAS Y FORMAS 2.2. FUNCION QUOTE 2.3. FUNCIONES DE SELECCION 2.4. FUNCIONES DE CONSTRUCCION 2.5. OTRAS FUNCIONES 11 12 12 15 18

TEMA 3. FUNCIONES PARA OPERAR CON NUMEROS


3.1. OPERACIONES ARITMETICAS 3.2. FUNCIONES MATEMATICAS 3.3. FUNCIONES PARA COMPARAR NUMEROS 3.4. PREDICADOS NUMERICOS 23 24 25 25

TEMA 4. PREDICADOS Y OPERADORES LOGICOS


4.1. PREDICADOS DEFINIDOS EN LISP 4.2. OPERADORES LOGICOS 27 29

TEMA 5. FUNCIONES DEFINIDAS POR EL USUARIO Y ESTRUCTURAS CONDICIONALES


5.1. DEFINICION DE FUNCIONES 5.2. ESTRUCTURAS CONDICIONALES 5.3. DOCUMENTACION 31 36 38

TEMA 6. ENTRADA/SALIDA SIMPLE Y STREAMS


6.1. ENTRADA/SALIDA SIMPLE 6.2. STREAMS 41 43

TEMA 7. LIGADURAS, ASIGNACION Y AMBITO


7.1. LIGADURA DE LOS PARAMETROS EN LA FUNCION 7.2. FUNCION DE ASIGNACION 7.3. SENTENCIA LET 7.4. AMBITO LEXICO Y DINAMICO 45 47 48 50

Common Lisp TEMA 8. ESTRUCTURAS ITERATIVAS


8.1. ESTRUCTURAS ITERATIVAS 8.2. FUNCIONES ITERATIVAS PREDEFINIDAS

Programacin III

53 55

TEMA 9. MACROS Y OTROS TIPOS DE DATOS


9.1. DEFINICION, EXPANSION Y EVALUACION DE MACROS 9.2. LISTAS ASOCIATIVAS 9.3. LISTAS DE PROPIEDADES 9.4. ESTRUCTURAS DE REGISTROS 58 60 62 62

BIBLIOGRAFIA

65

Common Lisp

Programacin III

INTRODUCCIN Lisp fu propuesto por John McCarthy a finales de los 50. Se diseo como alternativa al modelo de computacin tradicional, es un lenguaje dirigido a procesado simblico en lugar de numrico, implementando el modelo de las funciones recursivas que proporcionan una definicin sintctica y semnticamente clara. Las listas son la base tanto de los programas como de los datos en LISP: es un acrnimo de LISt Processing. Lisp proporciona un conjunto potente de funciones que manipulan listas, implementadas internamente como punteros. Lisp ofrece a los programadores la potencia y generalidad de las estructuras de punteros, librndole de la manipulacin explcita de los mismos y de sus operaciones. LISP fu en sus orgenes un lenguaje simple y pequeo, consistente en funciones de construccin y acceso a listas, definicin de nuevas funciones, unos pocos predicados para detectar igualdades y funciones para evaluar llamadas a funciones. El nico fundamento de control era la recursin y las condicionales simples. Si se necesitaban funciones ms complejas se definan en funcin de las primitivas. A travs de los aos se le han ido incorporando funciones especializadas como estructuras de datos, control del programa, aritmtica de reales y enteros, entrada/salida, edicin de funciones LISP y traceado de la ejecucin de un programa. Estas extensiones han provocado la aparicin de diferentes dialectos del LISP: INTERLISP, MACLISP, FRANZLISP, ZETALISP, etc. Debido a esta proliferacin de dialectos, en 1983, la Agencia de Proyectos Avanzados de Investigacin propuso un dialecto standard del lenguaje conocido bajo el nombre de Common Lisp. En un principio, muchos de los programas desarrollados dentro del mbito de la Inteligencia Artificial se implementaron en LISP. Posteriormente, aparecieron formalismos de ms alto nivel como los sistemas de produccin, sistemas basados en objetos, deduccin de teoremas lgicos, sistemas expertos basados en reglas, etc. utilizando al Lisp como lenguaje para su implementacin. Muchos entornos modernos para la creacin de sistemas expertos estn implementados en Lisp. Pero incluso utilizando estas herramientas, es necesario frecuentemente acceder al Lisp para aumentar la funcionalidad del lenguaje de alto nivel. En algn sentido se podra considerar al Lisp como el "ensamblador" de la Inteligencia Artificial.

Common Lisp

Programacin III

Tema 1 SIMBOLOS, ATOMOS Y CONSES


Los objetivos fundamentales de esta tema son: conocer los diferentes tipos de datos que puede apuntar un smbolo en memoria, dar ejemplos de diferentes tipos de datos atmicos, escribir grficamente un smbolo con apuntadores del nombre en memoria, conocer si una lista es una lista de verdad o una lista punteada, conocer si un elemento es un tomo, una lista o ninguno de los dos. determinar el nmero de elementos del nivel superior de la lista, dibujar celdas y apuntadores que representen las estructuras CONS y las relaciones de sus elementos en memoria. convertir las celdas y apuntadores, que representan listas de verdad y listas punteadas, en listas con niveles nicos o mltiples.

1.1. SIMBOLOS LISP Y OBJETOS SIMBOLICOS


En Lisp todo son objetos que se representan mediante smbolos. La regla de oro de Lisp (lenguaje funcional) es la evaluacin de sus objetos. Existen diferentes reglas de evaluacin dependiendo del tipo de objeto. Cada smbolo tiene asociados cinco componentes que lo caracterizan: nombre imprimible, el valor, una definicin de funcin, una lista de propiedades y un paquete en el que se define dicho smbolo. Grficamente podemos representarlo como: SIMBOLO NOMBRE IMPRIMIBLE: VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE: Lisp siempre trabaja con apuntadores, por ello cada uno de los atributos mencionados NO contienen el dato sino un apuntador al mismo. El nombre imprimible corresponder con un nombre simple (secuencia de caracteres). Lisp en general, y a menos que se diga lo contrario, convertir automticamente las minsculas en maysculas. Los tipos de valores que puede tomar un smbolo son: el tipo atom (atmicos) como un nmero, un carcter, otro smbolo, un tipo string.

Tema 1

el tipo cons, como una lista. una estructura definida por el usuario. tipos de datos propios del usuario. En cualquier caso, es totalmente dinmico (depende del momento en el que se hace la asignacin). En un lenguaje convencional es necesario declarar el tipo del contenido. En Lisp no es necesario hacerlo, aunque lo permite. Adems un smbolo puede ser el nombre de una funcin cuyo cuerpo estar apuntado por la definicin de funcin. La lista de propiedades dar informacin del smbolo y el package, indica la pertenencia de un determinado smbolo a un package predefinido o de usuario. En un mismo paquete (package) no habr dos smbolos con el mismo nombre. En estos primeros temas haremos referencia exclusivamente a los dos primeros atributos del smbolo. Los dems iremos estudindolos, segn se vea su necesidad, a lo largo del curso.

1.2. TIPO ATOM


Los tomos son estructuras bsicas en Lisp. Todos los elementos que no son de tipo cons (construcciones de listas) son ATOMOS. Algunos ejemplos son: los nmeros: Lisp evala un nmero devolviendo ese mismo nmero. Enteros: -2, -1, 0, 1, 2, - Representan los enteros matemticos. - No existe lmite en la magnitud de un entero. Grficamente lo podramos ver como:
SIMBOLO NOMBRE IMPRIMIBLE: VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

-2 -2

Un nmero se apunta a s mismo. En general un tomo se apunta a s mismo. Racionales: -2/3, 4/6, 20/2, 5465764576/764 - numerador / denominador. - Notacin: fraccin ::= [signo] {dgito}+ / {dgito}+. Coma flotante: 0.0, -0.5 - Notacin : nmero-coma-flotante ::= [signo] {dgito}* punto-decimal {dgito} Complejos: #C(5 -3), #C(5/3 7.0) = #C(1.66666 7.0), #c(0 1) = n i. - Notacin : #c(a b) Donde a y b, representando la parte real y la parte
2 Apuntes

SIMBOLOS, ATOMOS Y CONSES

imaginaria, pueden ser enteros, fracciones o coma flotante. Los caracteres y strings son dos tipos de datos utilizados normalmente para manipular texto. En general, la funcin de evaluacin recae sobre s mismos. Caracteres: #\a, #\A - son objetos que comienzan por: #\ - #\a es evaluado como #\a - #\a en algunas operaciones se trata distinto que #\A Caracteres especiales NO IMPRIMIBLES: #\SPACE, #\NEWLINE Strings: "A", "hola" - Son utilizados a menudo para manipular textos y puede considerarse como series de caracteres o como vectores de caracteres. Un string puede examinarse para determinar qu caracteres lo componen. - Su representacin grfica podra ser:
SIMBOLO NOMBRE IMPRIMIBLE: VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

"A" "A"

- La representacin imprimible de un string comienza con " y finaliza por ". Por ejemplo, el string "hola" ser imprimido como "hola". Lo que significa que la evaluacin de un string es el propio string - Otros ejemplos. No slo las letras y en su caso los nmeros pueden formar parte de un string, pueden incluirse diferentes caracteres. Por ejemplo, el string siguiente: "hola adis" - Cuidado!, El carcter #\A no es equivalente al string "A". Los nombres de variables. El atributo valor del smbolo permite que dicho smbolo acte como una variable. Todo nombre de variable debe ser un smbolo atmico. El nombre imprimible del smbolo se usa como el nombre de la variable y el tipo de valor asociado puede ser un tomo o una construccin tipo lista. Los nombres de variables permitidos son: A, CONT, VALOR-FINAL, UNA-LISTA, ENT45 La evaluacin de un smbolo es ms complicada que la de los objetos (enteros, fraccionarios, coma flotante, complejos, caracteres y string) anteriormente vistos. En general, el LISP intentar aplicar la regla de devolver el valor del smbolo. Un ejemplo representado grficamente sera el de un contador con valor 2:

Common Lisp

Tema 1

SIMBOLO CONT NOMBRE IMPRIMIBLE: 2 VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

Por su parte la variable VALOR-FINAL puede apuntar a su vez a un smbolo que representa a una variable. Por ejemplo,

SIMBOLO NOMBRE IMPRIMIBLE: VALOR-FINAL VALOR: CONT DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:
> VALOR-FINAL CONT Si la variable apunta a una lista Lisp, el valor de la misma depender del contenido de la

lista. Constantes especiales. Existen dos constantes especiales que son smbolos reservados y corresponden con,
T true NIL false o lista vaca () Las constantes especiales apuntan a ellas mismas.

1.3. TIPO CONS


En Lisp hay muchas formas de agrupar elementos; por ejemplo los strings que ya han sido vistos. Sin embargo, la forma ms importante y verstil de agrupar objetos es mediante listas. (mesa silla lmpara estanteras) En general una LISTA es una estructura bsica de datos y una estructura de un programa en Lisp. Una lista est delimitada por los parntesis de abrir y cerrar y en su interior est formada por una secuencia de tomos y listas. Adems, una lista puede tener cualquier clase y nmero de elementos, separados entre s por un espacio, incluso no tener elementos (NIL o () ).
(1 2 3 4) ; lista de enteros (a b c d) ; lista de smbolos (#\a #\b #\c #\d) ; lista de caracteres (4 algo de "si") ; lista con entero, smbolos y un string. (sqrt 2) ; lista con 1er a funcin

Apuntes

SIMBOLOS, ATOMOS Y CONSES

(+ 1 3); " (- 4 6 1); " Todos los programas en Lisp se describen mediante funciones que se definen y llaman con

LISTAS. La estructura utilizada para representar la secuencia de elementos de una lista es la estructura CONS. Cada elemento de una lista se representa a travs de una estructura CONS formada por dos partes, CAR y CDR.

CAR

CDR

El CAR es la primera parte de la estructura y contiene un apuntador al primer elemento de la lista. El CDR es la segunda parte y contiene un apuntador a la siguiente estructura CONS que contiene los siguientes elementos de la lista o si no hay ms elementos un apuntador a NIL. Una lista es unidireccional. Por ejemplo: - El tomo A no es una estructura CONS.
Algunas LISTAS y su representacin con ESTRUCTURAS CONS - () NO TIENE UNA ESTRUCTURA CONS - (A)

A
- (1 2 3)

1
- (A (B C))

- HURACAN-ALICIA ((V-A-KmH 170)(HUMEDAD 100)(LOCALIZACION (NORTE 32.8)))

Common Lisp

Tema 1
SIMBOLO NOMBRE IMPRIMIBLE: HURACAN-ALICIA VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

NIVEL SUPERIOR

SUB-NIVEL V-A-KmH SUB-NIVEL NORTE 32.8 170 HUMEDAD 100 LOCALIZACION

- DIASLABORABLES (LUN MAR MIE JUE VIE)


DIAS-FUERA (LUN MIE)

En este ejemplo se ve una de las filosofias claras de Lisp, la reutilizacin de cdigo. Es importante no generar continuamente informacin ya existente. Pero de igual modo es necesario tener en cuenta cual es la informacin compartida para evitar efectos no deseados
SIMBOLO NOMBRE IMPRIMIBLE: DIASLABORABLES VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

LUN

MAR

MIE

JUE

VIE

SIMBOLO NOMBRE IMPRIMIBLE: VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE: DIAS-FUERA

Apuntes

SIMBOLOS, ATOMOS Y CONSES

Otra forma de expresar listas es mediante LISTAS PUNTEADAS(dotted list). Cuando el CDR de una estructura CONS apunta a un tomo en lugar de a una estructura CONS o NIL, la lista formada es una lista punteada. Por ejemplo, - Lista (A 4)

- Lista punteada (A . 4)

Las listas punteadas amenudo son llamadas tambin pares punteados. Lisp crea frecuentemente pares punteados (dependiendo de la implementacin) para crear estructuras de datos tipo lista, listas de propiedades y listas de asociacin, que las iremos mostrando (A . (B . (C . nil))) = (A B C) ms adelante. Existen funciones Lisp que permiten crear directamente estas listas. Otros ejemplos en los que se mezclan listas de verdad y listas punteadas pueden ser los siguientes. - ((LAS-LISTAS . PUEDEN) TENER VARIAS ESTRUCTURAS)

TENER

VARIAS

ESTRUCTURAS

LAS-LISTAS

PUEDEN

- ((LAS-LISTAS PUEDEN) TENER VARIAS ESTRUCTURAS)

TENER

VARIAS

ESTRUCTURAS

LAS-LISTAS PUEDEN

Cuando el ltimo elemento de una lista no apunta a NIL, se genera una lista punteada. La ventaja de las listas punteadas es el ahorro de una casilla CONS. Sin embargo, se pierde en flexibilidad ya que el tratamiento de una lista no podr depender de la marca de fin de lista. Adems en una lista , que apunta como ltimo elemento a NIL, permite la modificacin de la

Common Lisp

Tema 1

misma aadiendo nuevas casillas CONS. Sin embargo una lista punteada no permite estas modificaciones ya que se eliminara el ltimo elemento de la lista punteada. Es decir el segundo apuntador de la casilla CONS de la lista punteada quedara modificado por el nuevo valor. Un ejemplo errneo:
(LU MA MI JU VI SEMANA SABADO . DOMINGO FIN-DE-SEMANA)

Esta lista no es sintcticamente correcta. Una lista punteada precisa que despus del punto aparezca un objeto simple y despus un parntesis.

1. 4. EVALUACIN EN LISP
El Lisp Listener es el ciclo que realiza continuamente Lisp, siempre est a la espera de entradas. Cuando recibe una entrada, evala la s-expresin, espera al return, si la forma es atmica o espera a parntesis de cierre si es una lista. Finalmente imprime el resultado y el ciclo comienza de nuevo. A este ciclo se llama ciclo READ-EVAL-PRINT expresado a travs de las funciones Lisp (PRINT (EVAL (READ))). Por tanto, el evaluador es el mecanismo que ejecuta las formas y los programas LISP. Lisp siempre tratar de evaluar todo lo que se le suministre; esto es realizado a travs de la funcin eval; (eval form) se evala la forma y se devuelve el valor. As los nmeros, caracteres y strings tienen reglas de evaluacin simples cuya evaluacin devuelve su propio valor. Ejemplos, si se escribe el 3, Lisp devuelve el 3 si se escribe "esto es un string", Lisp devuelve "esto es un string". Vindolo desde un interprete Lisp, siendo el pront del mismo >: > 3 <return> ;; necesario pulsar return, indicando el final de la s-expresin 3 > esto es un string <return> esto es un string > Podemo decir que qualquier forma que NO es una lista espera un return para poder ser evaluada. >T <return> T > A <return> 5 (si X tiene el valor 5) Cualquier entrada en Lisp tendr una salida imprimible. Por ejemplo, las s-expresiones con quote devuelven siempre su propio valor. > 'A <return>

Apuntes

SIMBOLOS, ATOMOS Y CONSES

A > '(+ 2 3) <return> (+ 2 3) > Una forma de lista (sin quote) espera al cierre del parntesis: > (+ 2 3) 5 > (PRINT X) X ;; por la propia funcin de escritura print X ;; resultado de evaluacin de la funcin print > (PRINT "HOLA") HOLA HOLA > (* (+ 2 3) (/ 12 4)) 15 Aunque no es muy usual realizar llamadas explcitas a la funcin eval, se pueden incluso generar diferentes niveles de evaluacin. Por ejemplo, si asumimos los siguientes valores de las variables, X==>Y, Y==>Z, Z==>10, entonces >X Y ; tpico ciclo de evaluacin R-E-P > (EVAL X) Z ; los argumentos son evaluados antes de pasarlos a la funcin. > (EVAL (EVAL X)) 10

Common Lisp

Common Lisp

Programacin III

Tema 2 FUNCIONES PREDEFINIDAS SOBRE LISTAS


Los objetivos fundamentales de esta tema son: escribir expresiones como datos y "formas" en cdigo Lisp utilizando la funcin QUOTE, dar una explicacin de lo que debe hacer una funcin, escribir una "forma" con sintaxis correcta de Lisp y que cuando se invoque produzca el resultado deseado. predecir el resultado de las formas que llaman a funciones CAR, CDR y sus abreviados C****R. escribir formas que produzcan una salida dada, utilizando las funciones CAR, CDR y la forma abreviada C****R. predecir correctamente la salida para funciones CONS, LIST y APPEND. explicar como se producen los resultados de las evaluaciones de CONS, LIST y APPEND, en trminos de manipulacin de las estructuras CONS. dados ciertos datos, escribir la forma con llamadas a funcin CONS, LIST y APPEND para producir las salidas esperadas. llamar a primitivas que te permitan, dada una lista, determinar su longitud, el ltimo elemento, el elemento de una determinada posicin, si un elemento pertenece a la misma, etc.

2.1. EXPRESIONES SIMBOLICAS Y FORMAS


Los tomos y listas en Lisp son conocidos como expresiones simblicas. Cualquier tomo vlido o lista es una expresin simblica. Por ejemplo, ATOMOS: 5, A, "A ES UN STRING" LISTAS: (UNA LISTA DE ELEMENTOS)

(((A))) (+ 3 (* X (/ 100 (- Y Z)))) (DEFUN ADD2 (X) (+ X 2))


Una forma en Lisp es un objeto que puede ser evaluado. A un tomo no se le considera como una forma tipo lista. Algunos ejemplos de los que NO son formas de listas son, - 3 que se evala como 3, - A que se evala segn el apuntador del atributo valor del smbolo A. Ejemplos de los que s se considera formas de lista son: >> (+ 2 3)

11

Tema 2

5 > (+ 8 (* 3 4)) 20 > (SQRT 16) 4

2.2. FUNCION QUOTE


La funcin quote provoca que un objeto NO sea evaluado. Esta ser la forma de poder pasar una lista como datos. La forma de escribirlo es (QUOTE OBJETO) o bien, OBJETO. Por ejemplo, ATOMOS como objetos, > (quote X) X > X X > EQUAL EQUAL > 2 2 LISTAS como objetos > (QUOTE (A)) (A) > (A) (A) > (A B C) (A B C) > (PALABRAS (CONSTRUYE GATOS PERROS) (PALABRAS (CONSTRUYE GATOS PERROS))

2.3. FUNCIONES DE SELECCION


Las listas son conjuntos ordenados de elementos, tomos o listas, conectados. Para realizar la manipulacin de los elementos de una lista es importante tener acceso a sus elementos. Existen tres tipos importantes de funciones de seleccin de elementos: - CAR - devuelve el primer elemento de la lista. - CDR - devuelve toda la lista menos el primer elemento. - C****R - permite la concatenacin de funciones CAR Y CDR. Es decir, CADR,

12

Apuntes

FUNCIONES PREDEFINIDAS SOBRE LISTAS

CDDR, CADADR, etc. La funcin CAR, devuelve siempre el primer elemento de una lista. Su sintaxis es (CAR LISTA), o de una manera ms tcnica sera, (CAR CONS). Por ejemplo podramos tener la siguiente llamada (CAR (1 2 3)) -==> 1 Sin embargo, esto no funciona, ya que Lisp intentar evaluar la lista (1 2 3). Dar un ERROR. Intentar buscar una funcin definida con el nombre 1 y cuyos argumentos tomen valores 2 y 3 respectivamente. Como ya habamos comentado y para evitar que LISP evale una lista de datos (y en general cualquier objeto) utilizaremos quote/'. As para el ejemplo (CAR '(1 2 3)) - -> 1 anterior tendremos Ms ejemplos de esta funcin sera:

>> (CAR (A B C) ) >> (CAR (A B (C D) E) ) >> (CAR ((A B) C) ) >> (CAR ((A B C)) ) >> (CAR A) >> (CAR ()) / (CAR NIL) Es importante resear que la funcin CAR no resultado la direccin de un elemento que existe.

==> A ==> A ==> (A B) ==> (A B C) ==> ERROR ==> NIL genera un nuevo valor, sino que da como

La funcin CDR, para listas propias, de verdad o no punteadas, devuelve la lista sin el primer elemento. Es decir la funcin CDR devolver los elementos apuntados por el CDR de la primera estructura CONS de una lista (o CONS). Para una lista punteada, el CDR de una estructura CONS puede ser un tomo. Por tanto, en estos casos se devolver un tomo y no una estructura CONS. La sintaxis de esta funcin es (CDR LISTA) o de forma tcnica (CDR CONS).Ejemplos,

>> (CDR (A B C) ) ==> (B C) >> (CDR (A B (C D) E) ) ==> (B (C D) E) >> (CDR ((A B) C) ) ==> (C) >> (CDR ((A)) ) ==> NIL >> (CDR ((A B C)) ) ==> NIL >> (CDR A) ==> ERROR >> (CDR (A . B) ) ==> B El acceso a los elementos de una lista no es directo. Es decir, es necesario acceder a los elementos previos al que se quiere seleccionar.
Las funciones C****R, no son ms que una abreviacin de las formas CAR y CDR. Podemos invocar a las llamadas (C*R LISTA), (C**R LISTA), (C***R LISTA), (C****R LISTA), donde el * podr sustituirse por A, para invocar a CAR, o por D para invocar a

Common Lisp

13

Tema 2

CDR. Los caracteres incluidos invocan a las funciones respectivas en orden de derecha a izquierda.

>> (CADR (A B C) ) (CAR (CDR (A B C) ) ) ==> B >> (CDAR ((A B C) D E) ) (CDR (CAR A B C) ) ) ==> (B C) >> (CADDR (A B C D E) ) ==> C >> (CAR (CDDDDR (A B C D E) ) ) ==> E Sin la funcin CAR, este ltimo ejemplo hubiera devuelto (E). En general no es conveniente hacer uso de estas funciones ya que no son muy clarificadoras. Por ello es mejor utilizar funciones especficas.
Existe una serie de funciones equivalentes a la combinacin de las funciones CAR y CDR. (FIRST LISTA) (CAR LISTA) (SECOND LISTA) (CADR LISTA) (THIRD LISTA) (CADDR LISTA) (FOURTH LISTA) ETC. (TENTH LISTA) Estas funciones slo admitirn un argumento que ser una lista. Normalmente los ndices de las posiciones de los elementos empiezan del 0. LAST LIST. Esta funcin devolver la ltima estructura CONS de la lista. Por ejemplo,

>> (LAST (A B C)) >> (LAST (A (B C))) >> (LAST (1 2 3.5)) >> (LAST ())

==> ==> ==> ==>

(C) ((B C)) (3.5) NIL

Grficamente podemos ver algunos ejemplos.

>> (LAST (A (B C)))

==>

((B C))

>> (LAST ((A B C))

==>

((A B C))

14

Apuntes

FUNCIONES PREDEFINIDAS SOBRE LISTAS

>> (LAST A B . C))

==>

(B . C)

- ELT SECUENCIA INDICE. Esta funcin devolver el elemento de la secuencia que est en la posicin ndice. El primer elemento de la secuencia tiene el ndice en la posicin 0. Ejemplos,

>> (ELT (A (B C)) 1) ==> >> (ELT (A B) 3) ==> >> (SETQ ESTA-LISTA (A B C D E)) >> (ELT ESTA-LISTA 2) ==>

(B C) NIL ==> C (A B C D E)

2.4. FUNCIONES DE CONSTRUCCION


Las funciones con las que Lisp permite construir listas son CONS, LIST y APPEND. Con ellas deberemos ser capaces de construir listas de elementos, crear estructuras CONS, aadir ms elementos a una lista, concatenar listas, etc. FUNCIONES NO DESTRUCTIVAS CONS SEXP SEXP La funcin CONS, crea una nueva estructura cons. Sintcticamente podemos expresarlos como (CONS SEXP SEXP), donde SEXP son expresiones simblicas. El CAR de la casilla CONS apuntar a la primera SEXP y el CDR a la segunda SEXP. Obsrvese que si la segunda SEXP corresponde con un tomo entonces se crear una lista punteada ("impropia"). En los ejemplos se ver que la funcin CONS puede utilizarse para aadir un nuevo elemento al principio de la lista. Ejemplos,

>> (CONS A (B C D) ) >> (CONS (X Y) (B C D) ) >> (CONS ((X Y) (W Z)) ((A B)) ) >> (CONS A NIL ) >> (CONS NIL (A) )

==> ==> ==> ==> ==>

(A B C D) ((X Y) B C D) ( ((X Y) (W Z)) (A B)) (A) (NIL A)

Common Lisp

15

Tema 2

>> (CONS A B ) >> (CONS (A B) C ) >> (CONS NIL A )

==> ==> ==>

(A . B) ((A B) . C) (NIL . A)

LIST &REST ARGS La notacin &REST ARG implica que se permite cualquier nmero de argumentos. Es decir, se le puede pasar a la llamada de la funcin cualquier nmero de parmetros. La funcin LIST devuelve una lista formada con todos los elementos pasados como argumentos. Los argumentos debern ser expresiones simblicas, o s-expresiones vlidas. La sintaxis corresponder con llamadas del estilo (LIST SEXP SEXP ...). Algunos ejemplos,

>> s ==> (A B C) >> (LIST (A) (B) (C)) ==> ((A) (B) (C)) >> (LIST A (B C)) ==> (A (B C)) >> (LIST QUIERO (Y PUEDO) CREAR ((ALGUNA LISTA)) DIVERTIDA)
==> (QUIERO (Y PUEDO) CREAR ((ALGUNA LISTA)) DIVERTIDA)

>> (LIST (LIST (LIST A))) ==> (((A))) Como se ha podido observar Lisp construye nuevos datos pero slo en un nivel, el nivel superior.
APPEND &REST ARGS La funcin APPEND concatena los argumentos en una lista. Todos los argumentos, excepto el ltimo deben ser listas. Los argumentos que no sean listas no sern incluidos. Hablando tcnicamente, las casillas CONS de todos excepto el ltimo son copiados en el orden que preserve el orden de los argumentos. As en estas copias, el CDR de la ltima casilla de cada uno de los argumentos se enlaza con el siguiente. Sintcticamente lo indicaramos como (APPEND LISTA LISTA LISTA SEXP). Ejemplos,

>> (APPEND (A) (B) (C)) ==> (A B C) >> (APPEND (A) (B C)) ==> (A B C) >> (APPEND ((A)) ((B)) ((C)) ) ==> ((A) (B) (C)) >> (APPEND (PODRA) ((CREAR (UNA))) () (LISTA)) ==> (PODRA (CREAR (UNA)) LISTA) Quizs otros ejemplos ms interesantes son, >> (APPEND (APPEND (APPEND (A) ))) ==> (A) >> (APPEND (A) NIL) ==> (A) >> (APPEND NIL (B C)) ==> (B C) NIL es una lista y por tanto cumple los requerimientos de la definicin de APPEND. >> (APPEND (A) (B) C) ==> (A B . C) si el ltimo elemento no es una lista se obtiene una lista punteada. >> (APPEND A (B C)) ==> ERROR

16

Apuntes

FUNCIONES PREDEFINIDAS SOBRE LISTAS

si el primer argumento es un tomo distinto de NIL, entonces se produce un ERROR. Para ver ms claro el funcionamiento de la funcin append veremos algunos ejemplos grficamente.

>> (APPEND (A) (B) (C))


ENTRADA

===>(A B C)

C
SALIDA

copiados

>> (APPEND (A) NIL)

==> (A)

>> (APPEND (A) (B) C)


ENTRADA

==> (A B . C)

C
SALIDA

copiados

FUNCIONES DESTRUCTIVAS Las funciones presentadas hasta el momento, manipulan los valores dados como parmetros para obtener un valor. Los smbolos que representan dichos parmetros no son modificados, sin embargo existen otras funciones llamadas destructivas que modifican el contenido de algn parmetro. Por ejemplo:

(RPLACA lista elem), sustituye la cabeza de la lista con elem (setf (car lista) elem) Ejemplos: >> (setq a '(1 2 3)) << (1 2 3) >> (rplaca a 7) << (7 2 3)

->

Common Lisp

17

Tema 2

>> a << (7 2 3) Grficamente podramos verlo como:


A

1 7

(RPLACD lista elem), sustituye el resto de la lista con elem. Ejemplos: >> a << (7 2 3) > (rplacd a '(9)) << (7 9) >> a << (7 9) >> (rplacd a 6) << (7.6) >> a << (7.6) Grficamente podramos verlo como sigue:
A (1) (3) 7 6 (2) 2 3

;(1) ;(2)

;(3)

(NCONC lista1 ... listan), a diferencia de APPEND, NCONC devuelve su valor -> modificando el smbolo que expresa lista1 (setq lista1 (APPEND lista1... listan)). Ejemplos: >> (setq a '(1 2 3)) << (1 2 3) >> (setq b '(4 5 6))

18

Apuntes

FUNCIONES PREDEFINIDAS SOBRE LISTAS

<< (4 5 6) >> (nconc a b) << (1 2 3 4 5 6) >> a << (1 2 3 4 5 6) >> b << (4 5 6)


A

2 4

;al aplicar (nconc a b) 5 6

(PUSH item lista), aade un elemento a lista -> (setq lista (cons item lista)). Ejemplos: >> (push 9 b) << (9 4 5 6) >> b << (9 4 5 6)
B

(POP lista), elimina el primer elemento de lista -> (setq lista (cdr lista)). >> (pop b) << 9 >> b << (4 5 6)

Common Lisp

19

Tema 2

(NBUTLAST lista &optional n), elimina los n ltimos elementos -> de lista (setq lista (butlast lista n))
Ejemplos, >> (nbutlast b 2) << (4) >> b << (4)

20

Apuntes

FUNCIONES PREDEFINIDAS SOBRE LISTAS

2.5. OTRAS FUNCIONES


LENGTH SECUENCIA. Devuelve el nmero de elementos existentes en el nivel superior de la lista (o secuencia). Por ejemplo,

>> (LENGTH (A B C)) >> (LENGTH (A B . C)) >> (LENGTH ())

==> ==> ==>

3 2 0

MEMBER ITEM LISTA {&KEY {:TEST / :TEST-NOT / :KEY}}. La funcin MIEMBRO busca en el nivel superior de la LISTA un elemento que sea igual, EQL, que el ITEM. Si se encuentra un elemento que cumple esta condicin, la funcin devolver una lista cuyo CAR es el elemento buscado y el CDR es el resto de la lista. Por el contrario si no se encuentra ningn elemento se devolver NIL. Por defecto, el test que se realiza es EQL. Sin embargo, se puede expresar otro tipo de comparacin en la opcin KEY de la lista de parmetros. La opcin :TEST permite realizar comparaciones sucesivas del ITEM con cada uno de los elementos de la lista a travs del operador sealado despus de :TEST, hasta encontrar el primer elemento que cumple dicha condicin, es decir, que de NONIL. La opcin :TEST-NOT es semejante a la anterior, salvo que se detiene al encontrar el primer elemento en cuya evaluacin se obtenga NIL. Finalmente la opcin :KEY hace lo mismo que las anteriores pero aplica la funcin indicada en clave. Veamos algunos ejemplos,

>> (MEMBER C (A B C D E F)) >> (MEMBER Z (A B C D E F)) >> (MEMBER J (A B (I J) F))

==> ==> ==>

(C D E F) NIL NIL NIL

>> (MEMBER (X Y) (A B C (X Y) D)) ==> ; Su valor es NIL por que compara con EQL

Common Lisp

21

MODULO 2

>> (MEMBER (X Y) (A B C (X Y) D) :TEST #EQUAL) ==> ((X Y) D) >> (MEMBER 7 (3 5 7 9) :TEST-NOT #>) ==> (7 9)

22

Apuntes

Common Lisp

Programacin III

Tema 3 FUNCIONES PARA OPERAR CON NUMEROS


Los objetivos fundamentales de esta tema son: predecir correctamente la salida de formas que invocan a funciones aritmticas tales como +, -, * y /, predecir correctamente la salida de formas que invocan a funciones matemticas tales como INCF, DECF, SQRT, EXP, , predecir correctamente la salida para funciones que realizan comparaciones entre nmeros, tales como, =, /=, <, >, >= y <=, predecir correctamente la salida para predicados que actan sobre entradas numricas, tales como ODDP y EVENP. Comentarios. Las implementaciones actuales de Lisp son hoy en da muy rpidas en sus operaciones matemticas. Las formas de las expresiones matemticas son muy familiares para nosotros. Por ejemplo, el *- multiplicacin, /- divisin, <- menos que, >=- mayor o igual que, SQRT- raz cuadrada, SIN- seno, etc. Las formas Lisp para clculo, son consistentes con la estructura Lisp.

3.1. OPERACIONES ARITMETICAS


- SUMA, devuelve la suma de todos los argumentos que se pasan. - RESTA, devuelve el resultado de todas las restas sucesivas de los argumentos. - MULTIPLICACION, devuelve el producto de todos los argumentos dados. - DIVISION, devuelve como resultado un valor obtenido de la divisin del primer elemento con todos los dems. Si se pasa un nico argumento se devuelve el mismo. Se devuelve una fraccin cuando la divisin entre los nmeros no es entera. Puede obtenerse un entero como resultado de las funciones FLOOR, CEILING, TRUNCATE, ROUND y REM. Ejemplos:

>> (+ 2 3 4) >> (- 10 7 3) >> (- 7) >> (* 3 4 0.5) >> (/ 100 4 5) >> (/ 12 9) >> (/ 18 7)

==> ==> ==> ==> ==> ==> ==>

_________ _________ _________ _________ _________ _________ _________

23

Tema 3

>> (/ 25.0 10) >> (/ 7) >> (/ 2.0) >> (/ 48 24 (* 2 3)) Las operaciones aritmticas no modifican los Unicamente devuelven un valor.

==> ==> ==> ==> valores

_________ _________ _________ _________ de los argumentos que se les pasa.

3.2. FUNCIONES MATEMATICAS


- INCF, incrementa en una cantidad DELTA un valor PLACE. (INCF PLACE [DELTA]). Por ejemplo, si asumimos que el valor de C es 5, entonces

>> (INCF C 10) ==> 15 >> C ==> 15 >> (INCF C) ==> 16 >> C ==> 16 Mientras que si asumo que el valor de C es 5, y >> (- 1 C) ==> 4 >> C ==> 5 - DECF, decrementa en una cantidad DELTA, una valor PLACE. (DECF PLACE [DELTA]) Por ejemplo, si asumimos que el valor de C es 5, entonces >> (DECF C 10) ==> -5 >> C ==> -5 >> (DECF C) ==> -6 >> C ==> -6 Mientras que si asumo que el valor de C es 5, y >> (+ 1 C) ==> 6 >> C ==> 5 - SQRT, raz cuadrada de un nmero. (SQRT NUMBER) Por ejemplo, >> (SQRT 16) ==> 4 >> (SQRT 2) ==> 1.414 >> (SQRT -4) ==> #c(0 2) - EXPT, exponencial. Calcula el valor de un nmero elevado a otro nmero. Por ejemplo, >> (EXP 2 3) ==> 8

24

Apuntes

FUNCIONES PARA OPERAR CON NUMEROS

>> (EXP 3 -2) >> (EXP 3 0)

==> ==>

1/9 1

3.3. FUNCIONES PARA COMPARAR NUMEROS


Estas funciones se llaman normalmente predicados de nmeros que devuelven valores NIL o NO-NIL. - IGUALDAD (= NUM NUM ) >> (= 3 3.0) ==> T - NO IGUAL (/= NUM NUM) >> (/= 3 3.0) ==> NIL - MENOR QUE, secuencia estrictamente creciente de nmeros. (< NUM NUM ) >> (< 3 5 8) ==> T

>> (< 3 5 4) ==> - MAYOR QUE, secuencia estrictamente decreciente de nmeros. (> NUM NUM ) >> (> 8 5 3) ==>

NIL T

>> (< 8 3 5) ==> NIL - MENOR O IGUAL QUE, secuencia NO estrictamente creciente de nmeros. (<= NUM NUM ) >> (< 5 5 8) ==> T >> (< 9 9 4) ==> NIL - MAYOR O IGUAL QUE, secuencia NO estrictamente decreciente de nmeros. (>= NUM NUM ) >> (>= 9 7 7) ==> T
- MAXIMO - MIN (MAX NUM NUM ) (MIN NUM NUM )

>> (>= 8 9 8) ==> NIL >> (MAX 2 5 3 1)==> >> (MIN 2 5 3 1)==>

5 1

3.4. PREDICADOS NUMERICOS


Los siguientes predicados numricos aceptan un nico argumento. Para que un argumento se acepte sin ERROR, el tipo de argumento depender de la funcin utilizada. Los predicados son funciones que devuelven los valores: NIL => falso T => verdadero - NUMBERP, verifica si el tipo de objeto. Devuelve true si el objeto es un nmero. El argumento puede ser de cualquier tipo. (NUMBERP OBJETO) >> (NUMBERP 7) ==> T

>> (NUMBERP NOMBRE) ==> NIL - ODDP, verifica un argumento, que debe ser entero, y devuelve cierto si el entero es
impar.

Common Lisp

25

Tema 3

(ODDP ENTERO).

>> (ODDP -7)

==>

>> (ODDP 5.8) ==> ERROR - EVENP, verifica un argumento, que debe ser entero, y devuelve cierto si el entero es
par. (EVENP ENTERO)

>> (EVENP 8)

==>

>> (EVENP NOMBRE) ==> ERROR - ZEROP, verifica un argumento, que debe ser numrico, y devuelve cierto si el nmero es cero. (ZEROP NUMBER) >> (ZEROP 0.0) ==> T >> (ZEROP NOMBRE) ==> ERROR
Las funciones que no son primitivas en Lisp pueden ser escritas por el usuario. Las definiciones de funciones de usuario son el eje de construccin de Lisp. Algunos mdulos ms adelante veremos claramente estas definiciones, sin embargo presentamos un ejemplo de funcin para ir viendo la sintaxis de la misma. Ejemplo de paso de grados farenheit a celsius. Si F es la temperatura en grados farenheit, entonces la temperatura en grados celsius ser: C = 5/9 *(F-32) (defun CONVERSION-F-a-C (F)

(* (/ 5 9) (- F 32))

26

Apuntes

Common Lisp

Programacin III

Tema 4 PREDICADOS Y OPERADORES LOGICOS


Los objetivos fundamentales de esta tema son: evaluar expresiones utilizando predicados que verifiquen los parmetros de entrada segn un tipo de datos dado, evaluar expresiones utilizando predicados apropiados que verifican formas de igualdad, evaluar expresiones utilizando funciones lgicas, evaluar expresiones teniendo en cuenta salidas no-nil de ciertos predicados.

4.1. PREDICADOS DEFINIDOS EN LISP


Los predicados en Lisp son funciones en las que se verifican los argumentos para ciertas condiciones y devuelve NIL si la condicin es false o NO-NIL si la condicin es cierta. Los nombres de las funciones predicado predefinidas en Lisp, a menudo terminan en P: NUMBERP, INTEGERP, LISTP, ATOM, EQL y AND. En general los predicados servirn para compara valores de nmeros, verificar tipos de datos, detener el proceso iterativo y controlar el flujo de ejecucin. Predicados sobre tipos de datos. Todos los predicados que se muestran a continuacin devuelven T si son ciertos o NIL sino lo son. - ATOM OBJETO. Devuelve true si el objeto NO es una construccin CONS. - CONSP OBJETO. Devuelve cierto si el objeto es CONS. - LISTP OBJETO. Devuelve cierto si el objeto es CONS o NIL (la lista vaca). - NULL OBJETO. Ser cierto si objeto es NIL. - TYPEP OBJETO TIPO-ESPECICADO. Es cierto cuando el objeto pertenece al tipo definido en tipo especificado. Ejemplos,

>> (ATOM UNA) ==> >> (ATOM ()) ==> >> (ATOM "STRING") ==> >> (ATOM NIL) ==> >> (CONSP (UNA LISTA) ) >> (CONSP ()) ==> >> (LISTP NIL) ==> >> (NULL 5) ==>

___________ ___________ ___________ ___________ ==> ___________ ___________ ___________ ___________

27

Tema 4

>> (TYPEP (A B) CONS) ==> ___________ >> (NULL (TYPEP 5.2 INTEGER)) ==> ___________ Predicados de igualdad. Los objetos Lisp pueden verificarse a diferentes niveles de igualdad: igualdad numrica- =, igualdad estructural- EQUAL y de identidad representacional- EQL. Para verificar si dos objetos tienen el mismo valor, se usar normalmente el predicado EQUAL, que devolver T o NIL. Tanto EQUAL como EQL, aceptan slo dos argumentos.
- EQUAL X Y. Verifica si los objetos X e Y, son estructuralmente iguales. Es decir, los valores imprimibles de los objetos son iguales. Sintcticamente tendramos que expresarlo (EQUAL SEXPR SEXPR). Ejemplos

>> (EQUAL 5.0 5) >> (EQUAL NIL ()) >> (SETQ A WORD) >> (SETQ B WORD) >> (EQUAL A B) >> (SETQ L (A B C)) >> (EQUAL (A B C) L) >> (SETQ M L) >> (EQUAL L M) >> (SETQ N (A B C)) >> (EQUAL L N) >> (EQUAL L A)

==> ___________ ==> T

==> T ==> T ==> T ==> T ==> NIL

- EQL X Y. La funcin EQL testea si X e Y representan el mismo valor. Esta funcin puede devolver false aunque el valor imprimible de los objetos se igual. Esto sucede cuando los objetos apuntados por variables parecen los mismos pero tienen diferentes posiciones en memoria. Este predicado no conviene utilizarlo con strings, ya que su respuesta no ser fiable. Por el contrario se deber utilizar con variables y nmeros cuando sea preciso conocer si tienen la misma posicin en memoria. Sintcticamente tendramos (EQL SEXPR SEXPR), donde la sexpr se deber evaluar como un nmero o variable.

>> (EQL 5 5) >> (EQL 5 5.0) >> (SETQ A WORD) >> (SETQ B WORD) >> (EQL A B) >> (SETQ L (A B C)) >> (EQL (A B C) L) >> (SETQ M L) >> (EQL L M) >> (SETQ N (A B C))

==> T ==> NIL

==> T ==> NIL (NO FIABLE) ==> T (dos variables apuntan al mismo sitio

28

Apuntes

PREDICADOS Y OPERADORES LOGICOS

>> (EQL L N) >> (EQUAL L A)

==> NIL ==> NIL

4.2. OPERADORES LOGICOS


Lisp tiene tres de los operadores lgicos ms comunes como primitivas, AND, OR y NOT. Los dems pueden crearse a partir de estos. Los funciones AND y OR devuelven un valor cuando las condiciones son ciertas, en otro caso devuelven nil. Estas funciones no evalan necesariamente todos los argumentos. Una vez que se verifica la condicin se devuelve NONIL o T. Por ello es importante el orden en el que se colocan los argumentos. AND {FORM}*. La funcin AND evala sus argumentos en orden. Si cualquiera de los argumentos se evala a NIL, se detiene la evaluacin y se devuelve el valor NIL. Por el contrario si todos los argumentos son NO-NIL, devolver el resultado de la ltima evaluacin. Sintcticamente (AND SEXPR SEXPR ), est permitido cualquier nmero de argumentos. Ejemplos,

>> (AND T T T (* 2 5)) ==> 10 >> (SETQ X 3) >> (SETQ CONT 0) >> (INCF CONT) >> (AND (<= CONT 10) (NUMBERP X) (* 2 X)) >> (AND (EVENP X) (/ X 2)) ==> NIL

==>

OR {FORM}*. La funcin OR evala sus argumentos en orden. Si cualquiera de los argumentos se evala a NO-NIL, se detiene la evaluacin y se devuelve es valor. Por el contrario si todos los argumentos son NIL, la funcin OR devolver NIL. Sintcticamente (OR SEXPR SEXPR ), est permitido cualquier nmero de argumentos. Ejemplos,

>> (OR NIL NIL (NULL (A B)) (REM 23 13) ) >> (SETQ X 10) >> (OR (< 0 X) (DECF X) ) ==> T >> (SETQ X 10) >> (OR (CONSP X) (ODDP X) (/ X 2)) ==>

==>

10

NOT FORM. La funcin NOT evala un nico argumento. La funcin NOT devuelve T o NIL. Si los argumentos se evalan a NIL, entonces devuelve T, en otro caso NIL. Sintcticamente (NOT SEXPR), est permitido slo un argumento.

Common Lisp

29

Tema 4

Ejemplos,

>> (NOT NIL) ==> T >> (NOT T) ==> NIL >> (NOT (EQUAL A A) ) ==> NIL >> (SETQ X (A B C) ) >> (AND (NOT (NUMBERP X)) (NOT (ATOM X)) "ESTO ES CONS" )
==> "ESTO ES CONS"

30

Apuntes

Common Lisp

Programacin III

Tema 5 FUNCIONES DEFINIDAS POR EL USUARIO Y ESTRUCTURAS CONDICIONALES


Los objetivos fundamentales de esta tema son: saber la definicin, uso y sintaxis de DEFUN, predecir la salida de funciones definidas con defun y que definen ms de una forma, escribir expresiones DEFUN que incluyan documentacin y comentarios. escribir funciones utilizando opciones LAMBDA listas, escribir procedimientos utilizando la funcin COND, nombrar otras funciones condicionales utilizadas en otros lenguajes de programacin y permitirlas en Lisp como primitivas.
Una funcin es un objeto Lisp que puede invocarse como un procedimiento. Una funcin puede tomar una serie de argumentos y devolver uno o ms valores, pero al menos uno. Lisp tiene un gran nmero de funciones predefinidas, a menudo llamadas primitivas, aunque tambin permite la definicin de funciones propias. Lisp es un lenguaje funcional en el que todos los programas se escriben como colecciones de funciones y procedimientos. La definicin de la funcin se almacena en memoria como un atributo/objeto del smbolo. Por su parte una funcin se referenciar por el nombre imprimible de un smbolo cuando se realice una llamada a dicha funcin.
SIMBOLO NOMBRE IMPRIMIBLE: VALOR: DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

Por ejemplo la llamada a la funcin de suma (+ 2 3). La llamada a la funcin es una lista cuyo primer elemento es el nombre de la funcin y el resto formarn los parmetros de dicha funcin. Lisp comprobar que efectivamente el primer elemento de la lista se corresponde con algn funcin predefinida o del usuario. Los argumentos de la llamada a la funcin sern igualmente evaluados antes de pasrselos como informacin a la funcin (este procedimiento se usa siempre en las llamadas a menos que la funcin sea una macro o una forma especial). Si el argumento de una funcin es a su vez otra llamada a funcin, entonces se evala primero la funcin del argumento y el resultado de la misma se pasa a la funcin principal. Por ejemplo:

31

Tema 5

(+ 3 (* 2 4)) EVALUACION DE ARGUMENTOS: SALIDA: 11


ENTRADA:

(+ 3 8)

5.1. DEFINICION DE FUNCIONES


DEFUN (DEfine FUNction), permite al usuario definir sus propias funciones. En general una funcin consta de tres partes: nombre de la funcin, argumentos y cuerpo (lo que se suele llamar lambda expresin).

(DEFUN nombre-funcin lambda-lista {declaration: string-doc} cuerpo)


Donde nombre-funcin debe ser el nombre de un smbolo atmico, como para una variable, la lambda-lista es el conjunto de argumentos que se pueden pasar (hay varias opciones en las lambda-listas), de las declaraciones y documentacin hablaremos un poco ms adelante, y cuerpo es cualquier forma a evaluarse en secuencia cuando se invoca al nombre de la funcin. Como ya se vi anteriormente, la definicin de la funcin crea un nuevo apuntador en la representacin grfica que tenamos al atributo definicin de funcin. Ejemplo,

>> (defun PRIMERO (L) (CAR L) ) >> (PRIMERO (A B C))

==> PRIMERO ==> A

>> (defun RESTO (L) (CDR L) ) ==> PRIMERO >> (RESTO (A B C)) ==> (B C) El prarmetro L de la definicin se corresponde con una variable local, es decir, slo es accesible desde el interior de la funcin. Si hay una variable externa con igual nombre, la L que hace referencia dentro del cuerpo se refiere a la del argumento. Como decamos se permite hacer declaraciones e incluir documentacin en las funciones. Las declaraciones se utilizan para proporcionar informacin extra al sistema. A menudo son mensajes utilizados por el compilador. Las declaraciones tambin pueden aparecer al principio del cuerpo de ciertas formas como en las funciones. Los string de documentacin se utilizan para describir comandos y pueden imprimirse al invocar la funcin de documentacin de la funcin. Ejemplo, >> (defun CUADRADO (x) "Esta funcin devuelve el cuadrado de un nmero" (* x x) ; fin de CUADRADO ) ==> CUADRADO Esta funcin utiliza un string de documentacin y un comentario justo antes del ltimo

32

Apuntes

FUNCIONES DEFINIDAS POR EL USUARIO Y ...

parntesis de la funcin.

>> (CUADRADO 3) ==> 9 Qu sucede al definir la funcin CUADRADO? - Lisp crea un smbolo CUADRADO - incorpora en la casilla definicin de funcin el valor correspondiente a dicha funcin. Y cmo se evala y activa una funcin? La evaluacin de una funcin, cuando esta se define, consiste en el nombre de la propia funcin. Por ejemplo, al definir en LISP la funcin CUADRADO, devuelve como valor de la misma CUADRADO. >> (defun CUADRADO (x) (* x x) ) ==> CUADRADO Por otro lado, cuando se llama a una funcin con ciertos argumentos, el valor que devuelve dicha funcin se corresponde con la ltima forma ejecutada en el cuerpo de DEFUN. En la funcin CUADRADO, corresponde con la forma (* x x) >> (cuadrado 3) ==> 9 >> (cuadrado 2) ==> 4 >> (cuadrado (cuadrado 3)) ==> 81 >> (cuadrado (+ -4 5 (/ 3 1))) ==> 16 La definicin de una funcin puede incluir tantos argumentos como se estimen necesarios. Por ejemplo: >> (defun SUMA-CUADRADO (x y) (+ (cuadrado x) (cuadrado y)) ) >> (suma-cuadrado 2 3)
Se pueden definir tambin funciones sin parmetros:

==> ==>

SUMA-CUADRADO 13

>> (defun SALUDO () (print "hola a todos") ) ==> >> (saludo) "hola a todos" "hola a todos" La respuesta de LISP al llamar a la funcin SALUDOS, es mediante dos strings que correspondern: El primer string a la accin del comando PRINT, El segundo es el valor devuelto por la funcin saludo. Otro ejemplo para ver claramente este efecto: >> (defun escribe-los-dos (x y) (print x)
Common Lisp 33

SALUDO

==>

Tema 5

(print y) ) ==> >> (escribe-los-dos "hola" "qu tal?") ==> "hola" "qu tal?" "qu tal?"
La definicin general de una funcin con nombre es:

ESCRIBE-LOS-DOS

(defun nomb (p1 ... pn) cuerpo) donde (p1 ... pn) = ( {var}* [ &optional {var / (var [inic]) / (var [inic] [flag])}*] [ &rest var] [ &key {var / (var [inic])}*] [ &aux {var / (var [inic])}*)
Los usos y significados de cada una de estas opciones son las siguientes. &OPTIONAL {VAR / (VAR INIC) / (VAR INIC FLAG)}*. Los parmetros opcionales no precisan necesariamente argumentos en la llamada. Los parmetros que no tienen correspondencia en la llamada se identificarn con NIL o con el valor que se indique en la inicializacin. Las variables flag pueden utilizarse para indicar si un parmetro opcional se ha pasado como argumento en la llamada.

>> (defun ejemplo-opcional (a &optional (b 2 c) (d 3)) (list a b c d) ) ==> ejemplo-opcional >> (ejemplo-opcional 5) ==> (5 2 NIL 3) >> (ejemplo-opcional 5 6) ==> (5 6 T 3) Los elementos dados como valores de inicializacin se evalan. Por ejemplo, cambiando el ltimo parmetro opcional d, >> (defun ejemplo-opcional (a &optional (b 2 c) (d inicial-d)) (list a b c d) ) ==> ejemplo-opcional >> (setq inicial-d 4) ==> 4 >> (ejemplo-opcional 5) ==> (5 2 NIL 4) &REST VAR. Sigue a los parmetros opcionales y slo tiene un parmetro. En la llamada a la funcin primero se identifican los argumentos necesarios y luego los opcionales, cualquier otro argumento se agrupa en una lista que se identifica con VAR. Por tanto VAR se identificar con NIL si no hay ms argumentos. Por ejemplo >> (defun ejemplo-opcional-rest (a &optional (b 2) &rest x)

34

Apuntes

FUNCIONES DEFINIDAS POR EL USUARIO Y ...

(list a b x) ) >> (ejemplo-opcional-rest 5 6) >> (ejemplo-opcional-rest 5 6 7 8 9)

==> ==> ==>

ejemplo-opcional-rest (5 6 NIL) (5 6 (7 8 9))

&KEY {VAR / (VAR INIC)}*. La lambda lista de claves son variables especificadas despus de &KEY y se les puede dar valores de inicializacin. La forma de acceder a las claves en las llamadas de la funcin es a travs de los ":" seguidos del nombre de la clave y en su caso de una forma para darle un valor. Cualquier clave a la que no se hace referencia en la llamada se identifica con NIL. >> (defun ejemplo-op-rest-key (a &optional (b 2) &key c (d 2)) (list a b c d) ) ==> ejemplo-op-rest-key >> (ejemplo-op-rest-key 5 6 :c 10) ==> (5 6 10 2 ) >> (ejemplo-op-rest-key 5 6 :d 10) ==> (5 6 nil 10 ) >> (ejemplo-op-rest-key :d 15) ==> (:d 15 nil 2) La combinacin de opciones &key y &rest en la misma definicin de funcin, da problemas con algunas llamadas. Es necesario que aparezcan todas las referencias a las claves de la definicin, siempre y cuando despus existan ms parmetros en la llamada.
&AUX {VAR / (VAR INIC) / (VAR INIC FLAG)}*. No son parmetros de la funcin, y por tanto no se aceptan como argumentos de la llamada a la funcin. La opcin &AUX se utiliza para establecer variables locales de la funcin a las que se puede asignar un valor inicial. Algunos ejemplos de uso de los distintos tipos de parmetros:

>> (defun caso1 (a &optional (b 3) &rest x &key c (d 1)) (list a b c d x) ) ==> CASO1 >> (caso1 1) ==> (1 3 nil 1 nil) >> (caso1 5 'b :c 8) >> (caso1 1 6 :c 7) >> (caso1 1 6 :d 8 :c 9 :d 10) >> (defun caso2 (a b &key c d) (list a b c d) ) >> (caso2 1 2 :c 8) >> (caso2 :a 1 :d 8 :c 5) >> (caso2 :a :b :c :d) ==> ==> ==> ==> CASO2 (1 2 8 NIL) (:a 1 5 8) (:a :b :d NIL) ==> (5 b 8 1 (:c 8)) ==> (1 6 7 1 (:c 7)) ==> (1 6 9 8 (:d 8 :c 9 :d 10))

Funciones especiales sin nombre o lambda expresiones En algunas ocasiones, y lo veremos ms adelante, es deseable crear funciones sin

nombre. Estas funciones se conocen con el nombre de lambda-expresiones y tienen una

Common Lisp

35

Tema 5

estructura semejante a las de las funciones.

(lambda (p1 ... pn) cuerpo) Adems, el comportamiento es semejante al de la funcin. Ejemplos, >> ( (lambda (x y) (list x y) (cons (car x) (cdr y)) ('(a b) '(c d)) )

) ==> (a d)

5.2. ESTRUCTURAS CONDICIONALES


Los condicionales son formas que permiten tomar decisiones. Verifica y ramifica: verifica devolviendo NIL o NO-NIL (como cualquier funcin), y ramifica es el comando a ejecutarse posteriormente basndose en el resultado de la verificacin. Las condicionales se implementan como macros y formas especiales. Existen diferentes condicionales en Lisp, igual que en otros lenguajes: IF, CASE, COND, WHEN, UNLESS, TYPECASE IF TEST THEN [ ELSE]. La forma condicional IF puede expresar opcionalmente su parte THEN. Dos formas sintcticamente correctas seran: (IF FORMA-COND FORMATHEN) y (IF FORMA-COND FORMA-THEN FORMA-ELSE). Ejemplos

>> (defun dame-numero (obj) (if (numberp obj) "Es un nmero. Dame ms" "Esto no es un nmero") ) >> (dame-numero 4) >> (dame-numero 'a) ==> DAME-NUMERO ==> "Es un nmero. Dame ms" ==> "Esto no es un nmero"

COND {(TEST {FORMA}+) }+. Permite expresar varias condiciones, ejecutndose la primera que se cumple. La forma COND acepta cualquier nmero de listas cuyos elementos son formas. Estas listas estn formadas normalmente por un test seguido de cero o ms formas consecuentes. Estas formas se ejecutaran si y solo si el test devuelve un valor NONIL. La cabeza de las listas se evala secuencialmente hasta encontrar una que devuelva un valor NO-NIL, entonces las formas siguientes a la cabeza de esa lista se evalan y se sale de la forma COND. Si hubiera listas ms adelante cuyas condiciones (cabeza de lista) fueran tambin ciertas stas no se evalan y por tanto tampoco se ejecutan las formas incluidas en el resto. COND devolver el resultado de la ltima forma evaluada de la lista con un test NONIL. Si todos los test devuelven NIL, entonces COND devolver NIL. El ejemplo general para la sintaxis sera: (COND (TEST1 FORMA11 FORMA12 FORMA1N) (TEST2 ) ; no tiene ningn consecuente y se devolver el valor NO-NIL del test (TEST3 FORMA31 FORMA32 FORMA 3M)

36

Apuntes

FUNCIONES DEFINIDAS POR EL USUARIO Y ...

(TESTR ) ) Pero veamos algunos ejemplos concretos ms clarificadores:

>> (setq a 4) ==> 4 >> (cond ((numberp a) "Esto es un nmero") (t "Esto no es un nmero") ) ==> "Esto es un nmero. >> (defun mi-funcin (x) (cond ((< x 0) (- x)) ( t x) ) ;fin-cond ) ;fin-mi-funcin ==> mi-funcin >> (defun verificar (x) (cond ((< x 0) (print "NEGATIVO")) ((= x 0) (print "CERO")) ((<= X 10) (print "VALOR EN RANGO")) (T (print "VALOR MUY GRANDE") x) ) ;fin-cond ) ;fin-mi-funcin ==> mi-funcin
WHEN TEST FROMA1 ... FORMAN. Es equivalente a la forma IF sin opcin de incluir la forma else. Ejemplo,

>> (when (equal a 4) (print "cierto")) >> (when (equal a 3) (print "cierto"))

==> ==>

"cierto" "cierto" nil

UNLESS TEST FORMA1 ... FORMAN. Esta forma condicional difiere de las vistas hasta ahora en que se evaluarn las formas siempre que el resultado de la evaluacin del test sea NIL. Hasta ahora la evaluacin de las formas asociados a un test estaba condicionada a que stas dieran como resultado un valor NO-NIL. Ejemplos,

>> (unless (equal a 4) (print "cierto")) >> (unless (equal a 3) (print "cierto"))

==> nil ==> "cierto" "cierto"

CASE KEYFORM {(LIST { FORM}+)}+. Permite realizar ciertas acciones cuando una determinada forma tiene ciertos valores, expresados a travs de una lista. Por ejemplo,

>> (setq mes 'may) ==> may >> (case mes ((ene mar may jul ag oct dic) 31) ((ab jun sep nov) 30) (feb (if (zerop (mod ao 4)) 29 28) ) ) ==> 31
TYPECASE KEYFORM {(TYPE {FORMA}+)}+. Permite como en el caso anterior

Common Lisp

37

Tema 5

realizar una serie de acciones siempre que un determinado objeto sea de la clase indicada. Ejemplo,

>> (SETQ X 2) ==> 2 >> (TYPECASE X (string "es un string") (integer "es un entero") (symbol (print '(es un smbolo))) (otherwise (print "operador")(print "desconocido") ) ) ==> "es un entero" "es un entero "
PROGN {((VAR {INIT})/ VAR*)} DECLARACIONES CUERPO). Proporciona una forma de agrupar una serie de expresiones LISP. Cada una corresponde con un forma determinada y sern evaluadas en orden. Esto podra ser til en la utilizacin de la estructura condicional IF, por ejemplo:

(defun encontrar-mayor (a b) (if (a>b) (progn


(format t "~% El primer argumento, ~a es mayor que el segundo ~a ~%" a b)

a ) (progn
(format t "~% El segundo argumento, ~a es menor que el primero ~a ~%" b a)

b ) )

El valor devuelto por PROGN corresponde al de la ltima forma evaluada. PROG1 y PROG2, devuelven el valor de la primera y segunda forma respectivamente, mientras se evalan el resto de las formas. Si en la declaracin de un PROGN se incluyen variables locales, la asignacin de sus valores se hace en paralelo, al igual que suceda con LET. LISP da la posibilidad de que la asignacin de valores a las variables se realice secuencialmente mediante PROG*

(PROG* ...)
La devolucin de un valor para una forma puede hacerse explcito mediante RETURN.

(RETURN resultado) 5.3. DOCUMENTACION


Se puede hacer comentarios en cualquier lugar del programa siempre que se utilice el ";", de tal forma que despus de la coma comienza el comentario. Por convenio se utilizar: ;;;; 4 ";" y un blanco, al comienzo del fichero para indicar su contenido. ;;; 3 ";" y un blanco, para realizar comentarios sobre una funcin y aparecer en la lnea

38

Apuntes

FUNCIONES DEFINIDAS POR EL USUARIO Y ...

;;; posterior a la de definicin de funcin (cabecera). ;; 2 ";" y un blanco, se utiliza para comentar una lnea de cdigo. En la lnea inmediatamente ;; seguida a esta. ;slo un ; y sin blanco, se utiliza para explicar una lnea de cdigo en la misma lnea.
Ejemplo de un fichero comentado: ;;;; ******************************************************************* ;;;; Fichero: Ejemplo-comentario.lisp ;;;; Fecha-de-creacin: 20/02/2002 ;;;; Modulo: Apuntes de lisp. ;;;; Comentarios: Este fichero ha sido creado con fines didcticos. ;;;; Autores: Los profesores de I.A. 4 ;;;; (c) 2001 (F.I.S.S.) ;;;; ****************************************************************** (defun pareja (x) ;;; Esta funcin devuelve la pareja del personaje que se pasa como valor del ;;; parmetro x. (case x ;; se realiza la seleccin. ((Peter-pan) "Campanilla") ;Campanilla es una chica que vuela. ((Mortadelo) "Filemn") ;Ambos son agentes de la T.I.A. ( t "no tiene pareja") ) ;Fin de seleccin ) ;Fin de la funcin. ;;; Esperamos que haya encontrado su pareja con esta funcin. Si no modifquela ;;; siempre que lo crea necesario. ;;;; Fin del fichero.

Documentacin de una funcin Despus de la cabecera de una funcin (nombre y parmetros), se puede incluir comentarios mediante " comienzo de comentarios y " final de comentario

>> (defun nombre-funcin (p1 ... pn) "Aqu se pone el comentario" cuerpo ) << nombre-funcin Lisp permite acceder a esta documentacin a travs de la funcin DOCUMENTATION

Common Lisp

39

Tema 5

>> (DOCUMENTATION 'nombre-funcin) << "Aqu se pone el comentario"


Otra funcin interesante para conseguir informacin "on line" es DESCRIBE. (DESCRIBE nombre)

>> (defun simple (tomo numero &key (lista '(c d))) "Esta es una funcin ejemplo" (list tomo numero lista) ) << simple >> (describe 'simple) A SIMBOL NAME: "SIMPLE" DOCUMENTATION: FNS: "ESTA ES UNA FUNCION EJEMPLO" PACKAGE CELL: #PACKAGE USER FUNCTION CELL: (LAMBDA (ATOMO NUMERO &KEY .... ...... >> (documentation 'simple) "ESTA ES UNA FUNCION EJEMPLO"
Tambin es posible aadirle documentacin a las variables utilizando DEFVAR.

>> (defvar *alumnos* '(Jun Blas) "Contiene el nombre de todos los alumnos matriculados en I.A") *alumnos* >> (documentation '*alumnos*) "Contiene el nombre de todos los alumnos matriculados en I.A"

40

Apuntes

Common Lisp

Programacin III

Tema 6 ENTRADA/SALIDA SIMPLE Y STREAMS


Los objetivos fundamentales de esta tema son: predecir la salida de expresiones que llaman a funciones que realizan estas tareas (las descritas arriba), escribir expresiones que realicen estas tareas, escribir expresiones para escribir y leer utilizando una salida y entrada particular.

6.1. ENTRADA/SALIDA SIMPLE


Lisp tiene primitivas de funciones de entrad/salida. Las ms comnmente utilizadas son: READ, PRINT y FORMAT, aunque tambin veremos otras. Los dispositivos por defecto son, el de entrada el teclado y salida la pantalla, pero se puede redireccionar a otros dispositivos. Es decir, todas estas funciones toman un argumento opcional llamado input-stream o outputstream. Si este valor no es suministrado o es nil, se tomar por defecto el valor contenido en la variable *standard-input* que ser teclado o pantalla respectivamente. Si el valor es t se usar el valor de la variable *terminal-io*. Funciones de entrada. - READ, lee un objeto Lisp del teclado y devuelve dicho objeto. Esta funcin detiene la ejecucin del programa mientras no se termine con un RETURN. Sintcticamente tendramos (READ &optional stream) - READ-CHAR lee un carcter y lo devuelve como un objeto de tipo carcter. Su forma sintcticamente correcta es, (READ-CHAR &optional stream) - READ-LINE lee caracteres hasta encontrar un carcter #\newline. Y devuelve la lnea como un string de caracteres sin #\newline -> (READ-LINE &optional input-stream) - PEEK-CHAR lee un carcter del stream de entrada sin eliminarlo del stream. La prxima vez que se acceda para leer se leer el mismo carcter -> (PEEK-CHAR &optional peek-type input-stream) Si peek-type es t se saltarn los caracteres en blanco. Si su valor es nil no. - LISTEN devuelve t si hay un carcter disponible en el stream de entrada. Esta funcin es especialmente interesante para saber si ha llegado algn nuevo carcter desde el teclado ->(LISTEN &optional input-stream) Funciones de salida. - PRINT, toma un objeto Lisp como argumento y lo escribe en una nueva lnea con un blanco por detrs (introduce <RT> y blanco despus del objeto). Escribe los objetos por su

41

Tema 6

tipo, tal y como seran aceptados por un READ -> (PRINT objeto &optional stream) - PRIN1, es una versin de PRINT, imprime un objeto sin salto de lnea ni blanco. Trata los caracteres ESPACE -> (PRIN1 objeto &optional stream) - PPRINT, introduce slo <RT> -> (PPRINT objeto &optional stream) - PRINC, no escribe los objetos por su tipo. No trata los escapes -> (PRINC objeto &optional stream) - FORMAT, aparece como un mecanismo ms generalizado de dar la salida. Se indican directivas que son como variables situadas entre el string y comienzan con ~. Muchas directivas miran el siguiente argumento de la lista del format y lo procesan de acuerdo a sus propias reglas. Su forma es (FORMAT destino control-string &rest argumentos) - destino = nil/ t/ stream. Si se indica el nil, se crear un string con las caractersticas indicadas y ste ser lo que devuelva el format. Si se indica t, ser la salida por defecto y sino ser otro dispositivo indicado en stream. - control-string = contiene el texto a escribir y "directivas" - argumentos = lista con los parmetros para las "directivas" Se usan diferentes directrices para procesar diferentes tipos de datos e incluirlos en el string: ~A - Imprime un objeto cualquiera., ~D - Imprime un nmero en base 10 y ~S Imprime una expresin simblica. Adems se puede utilizar el smbolo @ junto con la directiva ~A, para justificar a la derecha valores numricos. No todas la directrices utilizan argumentos: ~% - Inserta una nueva lnea y ~| - Nueva pgina. Ejemplos,

>> (FORMAT T "STRING DE SALIDA")STRING DE SALIDA ==> NIL >> (SETQ VAR 5) ==> 5 >> (FORMAT T "STRING QUE INCLUYE ~A" VAR)STRING QUE INCLUYE 5 ==> NIL >> (FORMAT NIL "STRING QUE INCLUYE ~A" VAR) ==> STRING QUE INCUYE 5 >> (FORMAT T "ESCRIBE EL ARGUMENTO ~10@A JUSTIFICADO A LA DERECHA CON 10 ESPACIOS." 1000) ____________________________ ________________________________________________________________ ==> ___________________ >> (FORMAT T "~%LA PRIMERA RESPUESTA ES ~5@A ~%Y LA SEGUNDA RESPUESTA ES ~3@A " (* 5 3 2) (/ 3 5))____________________ ________________________________________________________________ ==> ________ - TERPRI realiza un salto de lnea -> (TERPRI &optional stream) Ejemplos de salida: >> (princ "hola") ==> hola "hola"

42

Apuntes

ENTRADA/SALIDA SIMPLE Y STREAMS

>> (print "hola")

==> "hola" "hola" >> (prin1 "hola") ==> "hola" "hola" >> (format t "hola") ==> hola NIL >> (format nil "hola") ==> "hola" >> (format nil "hola soy ~a, ~a" "yo" "Bonn") ==> "hola soy yo, Bonn" >> (format nil "~a~%~a" 'que? "donde?") ==> "QUE? donde?" >> (format nil "~(~a~)~%~a" 'que? "donde?") ==> "que? donde?" 6.2. STREAMS
Es un tipo de datos que mantiene la informacin sobre el dispositivo (fichero) al que est asociado. Har que las E/S sean independientes del dispositivo. Un stream puede estar conectado a un fichero o a un terminal interactivo. OPEN Esta funcin devuelve un stream. (OPEN nomfich &key :direction :element-type :if-exist :if-does-not-exist) donde nomfich ser un string/ pathname/ stream; :direction permitir sealar si el dispositivo va a ser de lectura-entrada, :input, salida-escritura, :output, o ambos, :io; :element-type a travs de esta opcin podremos indicar el tipo de objetos que tiene el fichero: character la unidad de transaccin es un caracter (pueden utilizarse las funciones read-char y write-char), (mod n) entero no negativo menor que n (pueden utilizarse las funciones readbyte y write-byte en estos ficheros); :if-exist y queremos escribir sobre l entonces tendremos dos opciones o machacar lo que ya existe, :overwrite, o seguir escribiendo desde el final, :append; por ltimo, con la opcin :if-does-not-exist si queremos abrir un fichero que no existe tendremos estas dos opciones o crearlo, :create, o dar un mensaje de error, :error. Algunos predicados con streams seran: - (STREAMP Objeto), dar T si objeto es un stream - (OUTPUT-STREAM-P stream), dar T si stream es de salida. - (INPUT-STREAM-P stream), ser T si stream es de entrada. CLOSE, Cierra un stream, desaparece la ligadura entre el fichero y el stream (en caso de

Common Lisp

43

Tema 6

estar ligado a l) -> (CLOSE stream &key :abort) * Algunos streams estandar *standar-input* *standar-output* *error-output* *terminal-io* Algunas funciones ms que manipulen ficheros. - (RENAME-FILE fichero nuevo-nombre), cambia de nombre un fichero. Si fichero es un nombre de stream, el stream y el fichero a l asociado resultan afectados. - (DELETE-FILE fichero), borra un fichero. Si fichero es un nombre de stream, el stream y el fichero a l asociado resultan afectados. - (FILE-LENGTH stream-de-fichero), devuelve la longitud de un fichero. Si esta no puede ser determinada devolver nil. - (LOAD fichero &key :verbose :print :if-does-not-exist), carga un fichero al interprete Lisp. A partir de ese momento el entorno Lisp contar con los objetos Lisp definidos en ese fichero. Las claves incluidas en la forma LOAD corresponden con: :verbose Si es t permitir al cargar el fichero, sacar un comentario sobre el *standaroutput* indicando las caractersticas del fichero que est siendo cargado. :print Si es t se saca un valor de cada expresin cargada sobre *standar-output*. :if-does-not-exist Si es nil devuelve nil; si es t el error correspondiente en caso de que lo haya.

44

Apuntes

Common Lisp

Programacin III

Tema 7 LIGADURAS, ASIGNACION Y AMBITO


Los objetivos fundamentales de esta tema son: dado un programa identificar las variables locales y libres del programa, dado un programa que tiene una variable especial con el mismo nombre que una variable ligada en un procedimiento, conocer cul es el valor de dicha variable en el procedimiento, cul su mbito para tener ese valor y cuando la variable toma su valor global, predecir la salida del procedimiento que usa variables lxicas y especiales, escribir la definicin de una funcin utilizando LET para crear y utilizar slo variables locales, escribir sentencias para definir variables globales, DEFVAR, DEFPARAMETER, y DEFCONSTANT.
Lisp ofrece varias formas para crear variables y disponer del control para determinar qu partes del programa pueden acceder a ellas. En este mdulo se presentan dos nuevos conceptos o trminos: ligadura o binding <--> corresponde con el par variable valor y entorno <--> coleccin de ligaduras que son accesibles en un momento determinado. Cada vez que se ejecuta una funcin, lo hace con un entorno nuevo, que consiste en el entorno en el que se defini la funcin y las variables con la lista de argumentos y valores con los que se les llama.

7.1. LIGADURAS DE LOS PARAMETROS EN LA FUNCION


Las variables creadas en la lista de argumentos de una DEFUN (parmetros formales) son normalmente locales para la funcin. La lista de parmetros organiza un espacio en memoria para el mbito de definicin de la funcin, que ser utilizado por los valores que se pasen a dicha funcin en la llamada.

>> (defun simple (string) string ) ==> SIMPLE >> (simple "vale") ==> "vale" >> string ==> ERROR, UNBOUND VARIABLE Esta variable slo tiene sentido dentro de la funcin simple, no tiene acceso desde fuera y por tanto si pretendemos tener informacin de dicha variable nos dar un ERROR Veamos ahora grficamente un ejemplo de definicin y llamada a una funcin.

45

Tema 7

DEFINICION DE FUNCION

LLAMADA A LA FUNCION

(defun SUM3 (X Y Z) (setf X (+ X Z)) )


A B

(SETF A 2 B 5 C 3) (SUM3 A B C)
C

Como se observa lo lista de parmetros apunta a los mismos valores que los correspondientes argumentos en la expresin de llamada. Cuando se termina la ejecucin de la funcin se desligan los valores de la lista de parmetros. Las variables de la lista de parmetros no afectan a las variables que se encuentran fuera del procedimiento. Veamos el efecto del ejemplo anterior.

Las variables ligadas, de la lista de argumentos de una funcin, no pueden ser accedidas por otras funciones llamadas en ejecucin desde la misma (a no ser que estos valores se pasen como argumentos de la nueva funcin llamada). Un ejemplo:

>> (defun menos-simple (string) (simple) ) ==> MENOS-SIMPLE >> (defun simple () string ) ==> SIMPLE >> (menos-simple "algo") ==> ERROR, UNBOUND VARIABLE Al hacer una llamada a la funcin MENOS-SIMPLE con un argumento (asignndole el valor "algo") la llamada interna a la funcin SIMPLE me dar un ERROR. Esta es la norma general, sin embargo puede suceder en algunas implementaciones que la funcin interna tenga acceso a las ligaduras de la funcin padre.

46

Apuntes

LIGADURAS, ASIGNACION Y AMBITO

7.2 FUNCION DE ASIGNACION


La funcin SET puede utilizarse para alterar el valor de una variable dinmica. Antes de realizarse la asignacin se evalan los argumentos y devolver el valor de la ltima evaluacin realizada. (SET FORMA-SIMBOLO FORMA-VALOR), donde FORMA-SIMBOLO ser una forma que dar como valor la direccin de un nombre de smbolo y FORMA-VALOR es el valor que se asignar despus de la evaluacin. Ejemplos, si asumimos que el valor de X es Y y que Y tiene el valor 5,

>> X >> Y >> (SET X 10) >> X

==> ==> ==> ==>

Y 5 10 Y

; obsrvese que no se ha modificado

>> Y ==> 10 La asignacin que se realiza sobre la variable X no modifica dicha variable ya que se asigna el valor 10 a la evaluacin de la variable X, es decir, a Y.
La funcin SETQ asigna un valor a una variable. Su sintaxis es, (SETQ {VAR FORM}+). La Q de SETQ es un mnemotcnico para la aplicacin de la funcin quote. Los argumentos impares de la funcin no son evaluados. (SETQ VAR FORM VAR FORM ), puede haber un nmero par de argumentos. Las evaluaciones de las formas y las asignaciones (primero se evala y luego se asigna) se realizan secuencialmente, devolviendo el valor de la ltima evaluacin efectuada. Ejemplos,

>> (SETQ X 5) ==> 5 >> (SETQ NOMBRE "MARIA") ==> "MARIA" >> (SETQ FRUTA (CAR (MANZANA PERA ))) ==> MANZANA Los valores de un smbolo pueden cambiarse con las funciones de asignacin setq y setf.
SIMBOLO NOMBRE IMPRIMIBLE: EDAD-BARBARA VALOR: 2 DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

>> (SETQ EDAD-BARBARA 3)


SIMBOLO NOMBRE IMPRIMIBLE: EDAD-BARBARA VALOR: 3 DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

Common Lisp

47

Tema 7

La funcin SETF, es utilizada como las SETQ para realizar asignacin de valores a variables. Su sintaxis es (SETF {LUGAR FORM}+). SETF utiliza la forma lugar para determinar una localizacin o direccin en la que hay que realizar la asignacin. El lugar queda restringido a variables o alguna forma de funcin aceptable que normalmente evala un lugar al que asignar un valor. Tal y como la haca SETQ, realiza las evaluaciones y asignaciones secuencialmente, devolviendo el valor de la ltima evaluacin realizada. Ejemplos,

>> (SETF NOMBRE "MARIA") ==> "MARIA" >> (SETF X (A B C) ) ==> (A B C) >> (SETF (CAR X) (CAR (1 2 3)) ) ==> 1 >> X ==> (1 B C) 7.3. SENTENCIA LET
Let permite crear variables locales interiores a una funcin. Su forma general consta de dos partes asignacin de variables y cuerpo , y lo podemos expresar: (LET ({VARIABLE}* / {VARIABLE FORMA}*) {DECLARATIONS}* CUERPO La asignacin de variables es una lista de listas donde cada lista consta de un nombre de variable y una forma a evaluar. Cuando un LET es llamado las formas se evalan asignando paralelamente valores a todas las variables. Por su parte el cuerpo del LET es como el cuerpo de un DEFUN. Cualquier valor previo que tuvieran variables con el mismo nombre se guardarn y se restaurarn al finalizar el LET. Las operaciones incluidas en el LET son evaluadas en el entorno del LET. Y por otra parte las variables creadas en el LET son locales (al LET) y por tanto no pueden ser accedidas desde el exterior (tal y como sucede con DEFUN).

>> (LET ((a 3) (b 4)) (+ (sq a) (sq b)) ) ==> 25 Tal y como suceda en la llamada a una funcin, la ejecucin de un LET devuelve el valor de la ltima evaluacin efectuada. >(defun AREA-CIRCULO (dimetro) (LET ((radio (/dimetro 2))) (* radio radio pi) ) ) ==> AREA-CIRCULO >> (area-circulo 4) ==> 12.566370614 Es importante recalcar que la funcin LET asigna valores en paralelo y por tanto una funcin como: >> (defun suma-algo (x) (let (( x (+ x 2)) (y (+ x 1)) ) y)) ==> SUMA-ALGO >> (suma-algo 3) ==> 4 Si lo que queramos es obtener como resultado de esta funcin 6, hay que utilizar la
48 Apuntes

LIGADURAS, ASIGNACION Y AMBITO

asignacin secuencial de valores mediante LET*, que realiza la asignacin de variables de manera secuencial. Veamos algunos ejemplos ms.

(setf L (1 2 3)) (let ((A (CAR L)) (B (CADR L)) (C (CADDR L)) ) (PRINT (+ A (+ B C))) ) En este ejemplo las variables A, B y C son variables locales al LET. L es una variable libre. Si la sentencia LET estuviera dentro de una funcin sera mejor pasar el valor de L como parmetro para asegurarse el valor deseado. Es mejor asegurar explcitamente las intenciones de actuacin que depender del estado del entorno.
LET vs SET. Los parmetros del LET se ligan slo dentro del cuerpo del LET. Las asignaciones de SET dentro de un parmetro LET no crean ni modifican variables globales. Las asignaciones realizadas por el SET en variables libres crearn o cambiarn valores globales. Veamos algunos ejemplos.

>> (SETF X 5) >> (SETF E 0) >> (SETF TRIPLE 0) >> (LET ((D 2) (E 3) (CUADRUPLE)) (SETF DOBLE (* D X)) (SETF TRIPLE (* E X)) (SETF CUADRUPLE (* 4 X)) ) << 20 >> D << ERROR - UNBOUND VARIABLE

; variable no ligada

>> E << 0 >> DOBLE << 10 >> TRIPLE << 15 >> CUADRUPLE << ERROR - UNBOUND VARIABLE ; Los valores de las variables libres pueden modificarse en la ejecucin del LET (efecto lateral en la ejecucin del LET).
&AUX vs LET. En la definicin de la funcin tenemos la posibilidad de indicar variables auxiliares. (DEFUN NOMBRE ({PARAM}* &AUX {VAR}* / {(VAR INI)}* ) CUERPO). Las variables auxiliares en la lambda lista de definicin de la funcin no aceptan argumentos en la llamada a la misma. La clave &AUX se utiliza para establecer variables locales a la funcin y los valores de inicializacin se realizan secuencialmente (igual que
Common Lisp 49

Tema 7

LET*). Ejemplos,

(defun calculo-fisico (velocidad tiempo &aux distancia) ;; comienzo del cuerpo de la funcin (setf distancia (* velocidad tiempo)) ) ; fin calculo-fisico (defun calculo-fisico (velocidad tiempo &aux (distancia (* velocidad tiempo)) ) ; cuerpo ) ; fin calculo-fisico
OCULTACION. Recordar que cada vez que se llama a una funcin se crea un nuevo ENTORNO, con las ligaduras de la lista de argumentos con los valores de llamada.

>(defun hamlet (frases) (let ((frase (car frases))) (format t " ~a o no ~a ~% " frase frase) (let ((frase (cadr frases))) (format t "Esta es ~a. ~%" frase) ) ) ) ==> HAMLET Qu entorno se incluye en cada uno de los LET?, qu ligaduras existen en cada momento? Si llamamos a la funcin: >> (hamlet '( "ser" "la cuestin")) ==> ser o no ser Esta es la cuestin El entorno de variables que se ha creado para cada let es grficamente el siguiente:

(let ((frase (car frases))) (format t " ~a o no ~a ~% " frase frase) (let ((frase (cadr frases))) (format t "Esta es ~a. ~%" frase) frase = la cuestin frase = ser

frases = (ser la cuestin)

Si en un LET, incluido en una DEFUN, se crea una variable con el mismo nombre que alguno de los parmetros de DEFUN, el valor accesible dentro de LET ser el nuevo valor creado. Sin embargo, fuera del entorno del LET pero dentro del de la funcin el valor accedido ser el de la ligadura entre el argumento y el valor de llamada.

>> (defun algo (z) (let ((z 2)) (* z z) ) z) ==> ALGO >> (algo 5) ==> 5

50

Apuntes

LIGADURAS, ASIGNACION Y AMBITO

7.4. AMBITO LEXICO Y DINAMICO


Las variables, a menos que sean declaradas de otra forma, son de mbito lxico. Lo que se ha visto hasta ahora con respecto a la ligadura para los argumentos de una funcin es que slo pueden verse dentro del texto de dicha funcin (tienen mbito lxico). Las variables pueden declararse como especiales y en estos casos se dice que son de mbito dinmico. Es decir son variables libres que pueden ser accedidas desde cualquier parte del programa a partir del punto en el que han sido definidas. Las variables dinmicas se crean con una declaracin especial (DECLARE (SPECIAL NOMBRE-VAR)). Esta forma se utiliza para permitir a las variables locales convertirse en no locales.

>> (defun otra-funcin-mia (n) (declare (special n)) ; declaracin especial, envo de valor (mi-funcin) ) ==> OTRA-FUNCION-MIA >> (DEFUN mi-funcin () (declare (special n)) ; declaracin especial, toma de valor (1+ n) ==> MI-FUNCION Estas declaraciones pueden aparecer slo al comienzo de ciertas formas especiales como DEFUN y LET. Las variables libres se utilizan para comunicar informacin sobre el estado del programa, que puede ser interesante para varias funciones del programa; especialmente cuando no se quieren pasar como argumentos, o si muchas funciones necesitan el valor de dicha variable y sobre todo si necesitan modificarlo. Pero adems existe otra forma de declarar variables especiales para todas las funciones, sin necesidad de declararlas separadamente en cada una de ellas. Son dos las formas de hacerlo, declarndolas en el "nivel superior" del interprete(top level): - DEFVAR y DEFPARAMETER - DEFCONSTANT Esta es la idea de variable global utilizada en otros lenguajes de programacin. La forma sintcticamente correcta de las mismas es la siguiente: (DEFVAR nom-var [valor]), declara una variable global de nombre nom-var accesible desde cualquier parte del programa (desde cualquier funcin). (DEFPARAMETER nom-var [valor]), tiene las mismas caractersticas que DEFVAR, excepto que ser usado como parmetro y no como variable. (DEFCONSTANT nom-var valor), el valor permanecer constante en nom-var, si se intenta cambiar su valor dar error. Ejemplo: >> (defconstant *c* 36) << *c* >> *c* << 36

Common Lisp

51

Tema 7

>> (setf *c* 40) >>Error: *C* has constant value 36 and cannot be changed to 40

52

Apuntes

Common Lisp

Programacin III

Tema 8 ESTRUCTURAS ITERATIVAS


Los objetivos fundamentales de esta tema son:
realizar una programacin iterativa, al estilo de las estructuras iterativas de los lenguajes imperativos. Conocer la sintaxis y la utilizacin de estructuras: - LOOP, DO, DOTIMES y DOLIST, cada una de ellas con sus caractersticas propias. - MAPCAR, MAPLIST y MAPCAN, que permitir de manera breve expresar iteraciones mltiples.

8.1. ESTRUCTURAS ITERATIVAS


Veremos estructuras LOOP, DO, DO*, etc. LOOP {FORMA}*. Expresa una construccin iterativa que cicla continuamente, a menos que se le indique explcitamente que pare, evaluando las formas en secuencia. La forma de indicar la terminacin del ciclo es mediante RETURN. En general la evaluacin de la sentencia RETURN provocar la salida de cualquier sentencia iterativa. Ejemplo,

(loop (format t "escribe tu nombre, por favor.") (setq nombre (read)) (format t "escribe tu apellido.") (setq apellido (read)) (format t "es correcta la informacin introducida?") (setq s/n (read)) (if (equal s/n s) (return (cons nombre apellido) ) ) ) ;loop
DO ( {PARAM}* / {(PARAM VALOR)}* / {(PARAM VALOR INCRE)}*) (TESTEVALUACION {FORMAS}*) {FORMAS}*. La estructura DO tiene tres partes: lista de parmetros, test de final y cuerpo. La lista de parmetros liga las variables con sus valores iniciales y en cada ciclo se asignan nuevos valores dependiendo del funcin de incremento indicada. En la estructura DO, primero se activa la ligadura de los parmetros y despus se evala el test de final, y si no se cumple se ejecuta el cuerpo. Esta estructura podemos encontrarle semejanza con la de while ... do utilizada en otros lenguajes.

(DO

((var1 inic1 [paso1])... (varn inicn [pason])) (test-final resultado) declaraciones


53

; Asignacin de variables en paralelo ; Test-final se evala antes que cuerpo

Tema 9

cuerpo) Ejemplos: >> (defun exponencial (m n) (do ((resultado 1) (exponente n)) ((zerop exponente) resultado) (setq resultado (* m resultado)) (setq exponente (1- exponente)) ) ) ==> EXPONENCIAL >> (defun nueva-exp (m n) (do ((resultado 1 (* m resultado)) (exponente n (1- exponente))) ((zerop exponente) resultado) ) ) ==> NUEVA-EXP >> (defun nuevo-reverse (lista) (do ((l lista (cdr l)) (resultado nil (cons (car l) resultado))) ((null l) resultado) ) ) ==> NUEVO-REVERSE
DO* A diferencia del anterior realiza la asignacin de variables secuencialmente.

>> (defun exponente (m n) (do* ((resultado m (* m resultado)) (exponente n (1- exponente)) (contador (1- exponente) (1- exponente)) ) ;fin-parmetro ((zerop contador) resultado) ) ;fin-do ) ;fin-defun ==> EXPONENTE
DOTIMES permite escribir procedimientos sencillos con iteracin controlada por un contador. Ejecuta el cuerpo un nmero de veces determinado. (DOTIMES (var forma-limite-superior [forma-resultado]) declaraciones cuerpo) Cuando comienza el ciclo se evala la forma lmite superior, produciendo un valor n. Entonces desde el valor 0 incrementndose en uno hasta n-1, se asigna a la variable var. Para cada valor de la variable se ejecuta el cuerpo y al final, la ligadura con la variable se elimina y se ejecuta la forma resultado dando valor al DOTIMES. Si no tiene forma-resultado, su propsito es realizar efectos secundarios. Ejemplo,

>> (dotimes (cont 4) (print cont)) 0 1 2 3 NIL >> (defun exponencial-con-times (m n)


54 Apuntes

MACROS Y OTROS TIPOS DE DATOS

(let ((resultado 1)) (dotimes (cuenta n resultado) (setf resultado (* m resultado) ) ) ) ) ==> exponencial-con-times >> (exponencial-con-times 4 3) ==> 256 >> (defun palindromop (l &optional (inicio 0) (fin (length l))) (dotimes (k (floor (- fin inicio) 2) t) (unless (equal (nth (+ inicio k) l) (nth (- fin k) l)) ; salida antes de terminar todos los (return nil) ) ) )
ciclos

==> PALINDROMOP >> (palindromop (i am clever am i) T


DOLIST repite el cuerpo para cada elemento de una lista y como en el caso anterior al finalizar evaluar la forma resultado, siendo sta el valor de DOLIST. (DOLIST (var lista [resultado]) declaraciones cuerpo)

>> (dolist (x '(a b c)) (print x) ) A B C NIL >> (defun miembro (n lista) (dolist (l lista 'NO) (if (equal l n) (return 'SI) ) (print l))) >> (miembro 3 '(1 2 3 4 5)) 1 2 SI

==>

MIEMBRO

8.2. FUNCIONES ITERATIVAS PREDEFINIDAS Son prefcisamente en este tipo de funciones predefinidas, donde pueden tener sentido la definicin de funciones sin nombre o lambda expresiones (como prametro). (MAPCAR funcin lista1 ... listan) Va aplicando la funcin a los sucesivos car's de las listas. La funcin debe tener tantos argumentos como lista tiene el mapcar. Devuelve una lista con los resultados de las llamadas a la funcin. Utiliza LIST para construir el resultado. >> (mapcar #+ (7 8 9) (1 2 3)) >> (mapcar #oddp (7 8 9)) ==> (8 10 12) ==> (T NIL T)

Common Lisp

55

Tema 9

(MAPLIST funcin lista1 ... listan) Se aplica a los CDRs sucesivos de las listas. Devuelve una lista con los resultados de las llamadas a la funcin. Utiliza LIST para construir el resultado. >> (maplist #(lambda (x) (cons fuu x)) (a b c)) ==> ((fuu a b c) (fuu b c) (fuu c))
(MAPCAN funcin lista1 ... listan) Acta igual que mapcar pero utiliza la funcin NCONC para combinar los resultados.

>> (mapcan #lambda (x) (and (numberp x) (list x))) (a 1 b 2 c 3 d 4)) ==> (1 2 3 4)
(MAPCON funcin lista1 ... listan) Acta igual que maplist pero utiliza la funcin NCONC para combinar los resultados.

> >(mapcon #lambda (x) (and (numberp x) (list x))) (a 1 b 2 c 3 d 4)) ==> ((1 a 2 b 3 c 4 d) (2 b 3 c 4 d) (3 c 4 d) (4 d))
Otras funciones: MAPC, MAPL. Slo nos interesan por los efectos laterales, ya que no acumulan los resultados tal y como hacen MAPCAR y MAPLIST. Cuadro resumen: Actan sobre el CAR Devuelven el resultado construido con LIST Devuelven el resultado construido con NCONC Interesan por sus efectos laterales Ejemplos: MAPCAR MAPCAN MAPC Actan sobre el CDR MAPLIST MAPCON MAPL

>> (setq x '(1 2 3)) << (1 2 3) >> (mapcar #'(lambda (arg) (print (list arg arg))) x)

56

Apuntes

MACROS Y OTROS TIPOS DE DATOS

(1 1) (2 2) (3 3) << ((1 1) (2 2) (3 3)) >> x << (1 2 3) >> (mapc #'(lambda (arg) (print (list arg arg))) x) (1 1) (2 2) (3 3) << (1 2 3) >> x >> (1 2 3) >> (mapcan #'(lambda (arg) (print (list arg arg))) x) (1 1) (2 2) (3 3) << (1 1 2 2 3 3) >> x << (1 2 3) >> (maplist #'(lambda (arg) (print (list arg arg))) x) ((1 2 3) (1 2 3)) ((2 3) (2 3)) ((3) (3)) << (((1 2 3) (1 2 3)) ((2 3) (2 3)) ((3) (3))) >> (mapl #'(lambda (arg) (print (list arg arg))) x) ((1 2 3) (1 2 3)) ((2 3) (2 3)) ((3) (3)) << (1 2 3) >> (mapcon #'(lambda (arg) (print (list arg arg))) x) ((1 2 3) (1 2 3)) ((2 3) (2 3)) ((3) (3)) << ((1 2 3) (1 2 3) (2 3) (2 3) (3) (3))

Common Lisp

57

Tema 9

Tema 9 MACROS Y OTROS TIPOS DE DATOS


Los objetivos fundamentales de esta tema son: explicar el propsito de una MACRO en Lisp, escribir una MACRO bsica en Lisp utilizando DEFMACRO, explicar el propsito de MACROEXPANSION. escribir listas con la forma de listas de asociacin y listas de propiedades, escribir funciones que creen listas de asociacin, listas de propiedades y estructuras de registro, escribir funciones para aadir y acceder a datos de las listas de asociacin, listas de propiedades y estructuras de registro.
Lisp nos ofrece diversas alternativas para representar los datos: listas simples (de verdad), listas punteadas, listas de asociacin, listas de propiedades y estructuras de registro. La eleccin de la representacin de datos ms apropiada puede ser difcil. Planteemos algunas consideraciones: - Los datos son tanto ms complejos cuanto mas diversas son las caractersticas de los datos, - La necesidad de estructuras de datos ms potentes aumenta tanto ms cuanto mayor es la complejidad de los datos, - los programadores deben conocer ms de las caractersticas de la representacin interna de los datos si utilizan estructuras de datos menos potentes, - el tiempo de desarrollo puede reducirse utilizando estructuras ms complejas para datos complejos, - se sobrecarga la mquina con el uso de estructuras de datos potentes, - el mantenimiento de las estructuras es tanto ms fcil cuanto ms potentes son.

9.1. DEFINICION, EXPANSION Y EVALUACION DE MACROS


Las macros al igual que las funciones son formas que permiten agrupar acciones y darles un nombre. Expanden su cdigo en tiempo de compilacin, a diferencia de las funciones que lo hacen en tiempo de ejecucin. As, las macros son expandidas en primer lugar y luego interpretadas o compiladas, mientras que las funciones son interpretadas o compiladas directamente. No puede haber una funcin y macro con el mismo nombre. Adems, las macros se caracterizan por no evaluar los argumentos Desventajas:

58

Apuntes

MACROS Y OTROS TIPOS DE DATOS

Son difciles de depurar A veces hay que recompilar funciones despus de cambiar una macro. Tienen, al igual que las funciones, tres partes en su definicin: nombre, lista de
argumentos y cuerpo. Ejemplo de macro que suma dos nmeros. Es importante recordar que las macros no

evalan sus argumentos.

>> (defmacro sq (x) (list '* x x)) << SQ >> (defun sumq (a b) (+ (sq a) (sq b))) << SUMQ >> (sumq 2 3) << 13
Una macro al igual que una funcin puede tener un nmero variable de argumentos y su cdigo es referenciado desde la celda funcin del smbolo. Cuidado! las macros no son
funciones y no pueden usarse con FUNCALL, APPLY o cualquier otra funcin de mapeo. A continuacin se explica paso a paso el proceso de ejecucin de una llamada a una

macro. Supongamos que la llamada es

>> (sq (+ 3 4)) << 49 a) se crea un entorno donde el argumento de la macro es x = (+ 3 4), esto es debido a que no se evalan sus argumentos en la llamada. Sin embargo, si sq hubiese sido una funcin el valor de x sera 7. b) El cuerpo de la macro (list '* x x) se evala en el entorno creado. El resultado de la evaluacin es lo que se denomina expansin de la macro. En nuestro caso concreto sera:
(* (+ 3 4) (+ 3 4)) c) El entorno en el que el cuerpo de la macro ha sido evaluado desaparece. d) una ejecucin normal de Lisp tiene lugar y el resultado que se obtiene es 49. Para saber que forma va a tener una macro cuando se expande se utiliza

MACROEXPAND:

>> (macroexpand '(sq 5)) << (* 5 5) >> (macroexpand '(sq (+ 3 4))) << (* (+ 3 4) (+ 3 4)) Existe un smbolo especial que se utiliza para la definicin de macros y que se denomina Backquote. Este proporciona una forma alternativa para escribir las macros de forma que quedan escritas creando un molde patrn en la forma en la que va a ser expandida la macro. As, nuestra macro sq se podra escribir: >> (defmacro sq (x) `(* ,x ,x))

Common Lisp

59

Tema 9

Todo aquello que esta detrs del backquote (`) no se evala, excepto lo que aparece precedido por una coma. Es decir, que el backquote sera igual que un quote pero que mira en su interior para ver si hay comas y evaluar lo que viene despus de ellas. Otro smbolo especial es la coma seguida por una arroba (,@) que hace que se elimine un nivel de parentizado. Por ejemplo, si queremos definir una macro que sume un nmero desconocido de enteros es muy interesante utilizar este nuevo smbolo:

>> (defmacro sumaent ( &rest lista-enteros) `(+ ,@lista-enteros)) << sumaent >> (macroexpand '(sumaent 1 2 5 6)) << (+ 1 2 5 6)

9.2. LISTAS ASOCIATIVAS


Son listas de sublistas, donde al primer elemento de cada sublista se llama clave y el resto dato. Es decir cada sublista es normalmente un para clave- un smbolo atmico- y dato- un tomo, ms de un tomo o una lista, puede aparecer ms de un elemento siguiente en la sublista). Si hay un nico dato y ste es un tomo, entonces se utiliza normalmente un par punteado. Son celdas CONS de la forma: ((indicador1.valor1)(indicador2.valor2)....(indicadorn.valorn)) Por ejemplo:

>> (defvar *listin* ' ((Pepe.212020)(Paco.213003)(Mara.253539))) << ((Pepe.212020)(Paco.213003)(Mara.253539)) Existen diferentes funciones predefinidas de manejo de listas asociativas ASSOC, acceso al primer para clave-datos -> (ASSOC clave a-list) >> (assoc 'Paco *listin*) << (Paco.213003) ACONS, aade un nuevo para punteado a un A-lista (lista de asociacin) (ACONS clave dato a-list)

->

>> (acons 'Marta 214004 *listin*) << ((Marta.214004)(Pepe.212020)(Paco.213003)(Mara.253539)) >> *listin* << ((Pepe.212020)(Paco.213003)(Mara.253539)) Acons no es destructivo, si se quiere cambiar la lista se debe de hacer utilizando setf: >> (setf *listin* (acons 'Marta 214004 *listin*)) << ((Marta.214004)(Pepe.212020)(Paco.213003)(Mara.253539)) >> *listin* << ((Marta.214004)(Pepe.212020)(Paco.213003)(Mara.253539))
REMOVE, se utiliza para eliminar elementos de la lista
60

->
Apuntes

MACROS Y OTROS TIPOS DE DATOS

(REMOVE (assoc clave a-list) a-list) Como resulta que no es destructiva deber de utilizarse acompaada de un setf si quiere variarse el valor de la lista:

>> (remove (assoc 'Pepe *listin*) *listin*) << ((Marta.214004)(Paco.213003)(Mara.253539)) >> *listin* << ((Marta.214004)(Pepe.212020)(Paco.213003)(Mara.253539)) >> (setf *listin* (remove (assoc 'Pepe *listin*) *listin*)) << ((Marta.214004)(Paco.213003)(Mara.253539)) >> *listin* << ((Marta.214004)(Paco.213003)(Mara.253539))
RASSOC, permite acceder a la primera clave que tiene asociado un dato concreto, devolviendo el par punteado correspondiente -> (RASSOC item a-list)

>> (rassoc 213003 *listin* :test (function equalp)) << (Paco.213003) Por defecto esta funcin hace una bsqueda utilizando la funcin eql. Un ejemplo de A-lista o lista de asociacin podra ser,
( (NOMBRE . JUAN URRETA) (SEXO . H) (EDAD . 28) (NACIMIENTO . 28 MAYO 1968))

clave dato clave dato clave dato clave Algunos ejemplos de utilizacin de las funciones ASSOC y RASSOC.

dato

>> (ASSOC FRUTA ((ANIMAL . PERRO) (CARNE . FILETE) (FRUTA . MANZANA)) ==> (FRUTA . MANZANA) >> (ASSOC HOBIES ((NOMBRE JUAN URRETA) (EDAD 28) (SEXO H) (HOBIES DORMIR COMER BEBER)) ==> (HOBIES DORMIR COMER BEBER) >> (RASSOC URRETA ((BARBARA . RODRIGUEZ) (RUBEN RODRIGUEZ) (JUAN URRETA) (MAITE URRETA) ) ==> (JUAN . URRETA) Las referencias a funciones en algunas de las primitivas anteriores se expresan formalmente como (FUNTION NOMBRE-FUNCION), y de modo abreviado #'NOMBREFUNCION. Ejemplos, >> #'+ ==> # <puntero a la definicin de la funcin "+"> >> #'EQUAL ==> # <puntero a la definicin de EQUAL> >> #'(LAMBDA (X Y) (+ X Y)) ==> # <puntero a la representacin>

Common Lisp

61

Tema 9

9.3. LISTAS DE PROPIEDADES


Es una lista que contiene un nmero par de elementos (que puede ser cero). Cada par de elementos de la lista constituye una entrada; su primer tem es el nombre de la propiedad y el segundo el de su valor: (propiedad1 valor1 propiedad2 valor2 .....propiedadn valorn) GET, permite el acceso al valor de una propiedad -> (GET lista-propiedades propiedad) La creacin de una lista de propiedades y la incorporacin de nuevas propiedades, se realiza combinando las funciones GET y SETF. Ejemplos,

>> (defvar *Juan*) >> (setf (get '*Juan* 'pelo) 'negro (get '*Juan* 'ojos) 'claros (get '*Juan* 'barba) 'si ) << si >> (get '*Juan* 'ojos) << claros >> *Juan* << nil Se puede crear listas de propiedades para un objeto que no est definido.
SYMBOL-PLIST, devolver la lista de propiedades asociada al smbolo.

>> (symbol-plist '*Juan*) << (barba si ojos claros pelo negro) >> (setf (get '*Juan* 'tez) 'morena) << morena >> (symbol-plist '*Juan*) << (tez morena barba si ojos claros pelo negro)
REMPROP, permite borrar una propiedad de una lista de propiedades asociada a un smbolo -> (REMPROP lista-propiedades propiedad). Ejemplos,

>> (remprop '*Juan* 'pelo) << pelo >> (remprop '*Juan* 'aos) << nil >> (symbol-plist '*Juan*) << (tez morena barba si ojos claros) 9.4. ESTRUCTURAS DE REGISTRO
Corresponde con el concepto de registro en Pascal y de estructura en C. DEFSTRUCT, la definicin de una estructura se realiza indicando el nombre para ese tipo de estructura y los campos o registros, donde cada campo puede ser un smbolo (nombre del campo) o una lista con dos elementos, un smbolo (nombre del campo) y un valor
62 Apuntes

MACROS Y OTROS TIPOS DE DATOS

(inicializacin). En general una estructura se define:

(DEFSTRUCT (nombre opcion1 ... opcionn) (campo1 valor-defecto opcion11 ... opcion1m)...) opcioni: (:type list) (:include nom-estructura) opcionij: (:type integer) (:read-only t) La opcin type permite especificar los tipos vlidos para un determinado campo. Readonly no permitir ningn tipo de modificacin sobre ese campo, lo que significa que slo se podr indicar un valor en tiempo de creacin. Una vez definida una estructura, automticamente se definen todas las funciones de creacin y acceso a campos para esa estructura. Un ejemplo, >> (defstruct MANO (nombre " " :TYPE string :READ-ONLY t) ;nombre jugador (cartas () :TYPE list) ;mano en el juego (valor 0 :TYPE integer) ;puntos en mano ) ;fin definicin de la estructura Otro ejemplo para crear la estructura empleado con las siguientes caractersticas es: >> (defstruct empleado nombre departamento puesto ) Automticamente se habrn creado las siguientes funciones de acceso: - ACCESO A LA ESTRUCTURA: make-empleado - ACCESO AL CAMPO: empleado-campoi
La creacin de estructuras, una vez definida una estructura se realizar con la combinacin de SETF y MAKE-nombre-estructura. Por ejemplo,

>> (setf emp1 (make-empleado)) ;; Crea un instancia de empleado llamada emp1. >> (setf emp1 (make-empleado :nombre 'Juan :departamento 'informtica :puesto programador ) ;; Crea una instancia de empleado dando valor a sus campos.

El acceso al valor de un registro se realiza mediante una forma, expresada en una lista cuya cabeza es el nombre de la estructura, un guin, y el nombre del registro al que se quiere acceder y un segundo elemento de la lista que ser el nombre de la estructura concreta a la que quiero acceder. >> (empleado-nombre emp1) << Juan La modificacin de un registro concreto de una estructura se realiza con la combinacin

Common Lisp

63

Tema 9

de SETF y ACCESO-CAMPOi, tal y como se muestra en el ejemplo siguiente.

>> (setf (empleado-nombre emp1) 'Miguel) Ejemplo >> (Defstruct (Directivo (:include empleado)) (Despacho Ala-oeste)) << DIRECTIVO. >> (Setf Luis (make-directivo :nombre Luis :departamento Sistemas :puesto Director :despacho 2Ala-oeste))

64

Apuntes

Common Lisp

Programacin III

BIBLIOGRAFIA

GNU Common Lisp: comunidad, 2007. XLISP-PLUS version 3.04 Help User Guide References. Common Lisp: The language. Guy Steel- Digital Press, 1984. Lisp. Patrick Henry Winston. Berthold Klaus Paul Horn. Addison-Wesley, 1989. Lisp (Tercera Edicin). Patrick Henry Winston. Berthold Klaus Paul Horn. Addison-Wesley

Iberoamericana, 1991.
Lisp Programazio-Lengoaia. J.R. Bastarrica, K. Sarasola. Inprimategia BOAN S.A. 1991. Common Lisp Programming. Education & development center. Texas instruments- data

systems group, 1986.

65