Anda di halaman 1dari 46

Progra m a c i n I I I

P a r te I I - P r o gr a ma c i n F u nc io na l

Lic. Ricardo Monzn

Apunte de Programacin Funcional III

Programacin

Programacin Funcional
Caractersticas de los lenguajes funcionales
Los lenguajes funcionales se basan en el concepto de funcin, por tanto, el objeto bsico y fundamental que manejamos son las funciones, que se pueden considerar las principales estructuras de control en este tipo de lenguajes. La base fundamental para comprender este tipo de lenguajes consiste en ver los programas y aplicaciones expresados a travs de funciones y aplicacin entre funciones. Las caractersticas fundamentales de estos lenguajes se exponen a continuacin: Utilizacin de funciones sobre elementos de primer orden. Utilizacin de funciones polimrficas, es decir, aquellas cuyo tipo devuelto depende del tipo de los argumentos. Utilizacin de funciones de orden superior, es decir, aquellas funciones que aceptan en su lista de argumentos otras funciones. Evaluacin perezosa (o lazy), es decir, las expresiones no se evalan hasta que no se necesitan los resultados. Es, justamente, lo contrario de la evaluacin eager (ansiosa), donde la evaluacin de los argumentos se realiza antes de aplicar la funcin. La evaluacin perezosa nos proporciona la ventaja de trabajar con listas potencialmente infinitas. Existencia de un sistema de tipos fuerte. Uso del Patter Matching: comprobacin de patrones.

Vistas las caractersticas fundamentales de los lenguajes funcionales, estos pueden clasificarse en dos tipos: Puros: aquellos en los que slo podemos aplicar funciones. Estas son las nicas estructuras de control. Posee evaluacin perezosa. Impuros: aquellos que poseen evaluacin ansiosa.

Apunte de Programacin Funcional III

Programacin

Comparativa entre imperativos

lenguajes

lgicos,

funcionales

Frente a los lenguajes declarativos e imperativos, los lenguajes funcionales ofrecen una serie de ventajas y de limitaciones. VENTAJAS Ofrecen un mayor nivel de abstraccin. Y pueden resultar ms fciles de usar que los lenguajes lgicos, aunque, evidentemente, la facilidad de uso depende de la aplicacin y del programador, en particular. Posee un sistema de tipos fuerte, de forma que el cdigo est ms protegido de errores. La responsabilidad del programador se ve reducida en este aspecto. Existen funciones de orden superior que permiten manejar argumentos de tipo funcin. Pueden trabajar con datos potencialmente infinitos, ya que se aplican tcnicas de evaluacin perezosa en los lenguajes funcionales puros. Los lenguajes funcionales son muy adecuados para realizar programas donde se exija un alto grado de paralelismo. Facilitan el trabajo en mquinas paralelas. Los errores se pueden depurar fcilmente. Esto constituye una ventaja frente a los lenguajes lgicos que hemos visto, cuyo seguimiento puede resultar bastante complicado. Es muy fcil pasar de la especificacin del problema a la implementacin, debido al alto grado de abstraccin que ofrecen. Transparencia referencial. Este concepto es clave en los leguajes funcionales. Una expresin siempre proporciona el mismo resultado, es decir, es evaluada, siempre, del mismo modo. Esto no es cierto en los lenguajes imperativos donde pueden existir efectos laterales. Gracias a la transparencia referencial podemos usar la operacin de sustitucin: la aplicacin de una funcin se puede sustituir por su definicin. Por ejemplo, par(doble(2*5))=par(doble 10)=par(2*10)=par(20)=true. LIMITACIONES Falta de estandarizacin.

Apunte de Programacin Funcional III

Programacin

Las implementaciones de los lenguajes que existen no son demasiado buenas.

El rendimiento de los programas puede resultar bajo. Las tcnicas usadas en estos lenguajes para el almacenamiento y manejo de la memoria no es demasiado adecuado ya que requieren mucha memoria. Poseen un recolector de basura (garbage collector).

Definicin y tipo de funciones


FUNCIONES Las funciones establecen relaciones entre dos conjuntos, imponiendo la restriccin nica de que un elemento no puede tener dos imgenes, (ver Figura 1).
Dominio Rango

f: D
(a, f(a))

Figura 1 Definicin de una funcin. Equivalente a f={(a,f(a))/aD} Podemos definir una funcin por extensin o por comprensin. En el primer caso, la funcin se define indicando todos los pares (a, f(a)). En el segundo caso, la funcin se define mediante la indicacin de una regla para calcular la imagen sobre el elemento del dominio. Ejemplo de lista definida por extensin par={(1,false), (7,false)...} (2,true), (3,false), (4,true), (5,false), (6,true),

doble={(0,0), (1,2), (2,4)...} Ejemplo de lista definida por comprensin par x=x mod 2==0 doble x=2*x

Apunte de Programacin Funcional III

Programacin

Se dice que dos funciones son equivalentes si tienen el mismo conjunto de pares. Adems hemos de tener en cuenta que el valor de una variable nunca cambia. FUNCIONES PARCIALES Son aquellas en las que la imagen de, al menos, un elemento no est definida. Ejemplo parcial de una funcin

Division x y (Ya que la operacin de divisin por 0 no est definida).

FUNCIONES TOTALES Son aquellas en las que todos los elementos del dominio tienen definida una imagen. Se puede realizar el cambio de funcin parcial a funcin total utilizando un elemento indefinido (o bottom). Este elemento nos sirve para conocer que elementos del dominio estn indefinidos y realizar un adecuado control de errores en nuestros programas. Ejemplo de funcin total obtenida a partir de una funcin parcial Division x y, y <> 0

Operaciones entre funciones


En muchos casos, resulta interesante realizar operaciones con funciones. Podemos aplicar, sencillamente, una funcin sobre un elemento del dominio para obtener su imagen. Por ejemplo, dada la funcin f(x,y)=x+y, podemos aplicar f(2,3) para obtener como resultado 5. Tambin podemos realizar otros tipos de operaciones ms complicadas entre funciones, por ejemplo la composicin de funciones que consiste en que el resultado de una funcin se puede usar como argumento para otra funcin. Por ejemplo, si tenemos la funcin par(x), y la funcin doble(y), par(doble(7)) devolver como resultado true.

Apunte de Programacin Funcional III

Programacin

INTRODUCCION A LISP
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 expertos en reglas, etc. utilizando en al Lisp. Lisp Pero como lenguaje para su implementacin. Muchos entornos modernos para la creacin de sistemas estn implementados 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.

Apunte de Programacin Funcional III

Programacin

Atomos, Listas y Conses.


El objetivo fundamental de este tema ser: 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.

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

Apunte de Programacin Funcional III

Programacin

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. 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.

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


Pgina 8

Apunte de Programacin Funcional III

Programacin

mismo. -2/3, 4/6, 20/2, 5465764576/764 Racionales: - 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 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 #\SPACE, #\NEWLINE Caracteres especiales NO IMPRIMIBLES: "A", "hola" Strings: - 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 "A" NOMBRE IMPRIMIBLE: VALOR: "A" DEFINICION DE FUNCION: LISTA DE PROPIEDADES: PACKAGE:

- 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

Pgina 9

Apunte de Programacin Funcional III

Programacin

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:
SIMBOLO NOMBRE IMPRIMIBLE: CONT VALOR: 2 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,

Pgina 10

Apunte de Programacin Funcional III

Programacin

T NIL

true false o lista vaca ()

Las constantes especiales apuntan a ellas mismas.

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 genera 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) (a b c d) (#\a #\b #\c #\d) (4 algo de "si") (sqrt 2) (+ 1 3); (- 4 6 1); ; lista de enteros ; lista de smbolos ; lista de caracteres ; lista con entero, smbolos y un string. ; lista con funcin ;" ;"

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

Pgina 11

Apunte de Programacin Funcional III

Programacin

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 - () (A) NO TIENE UNA ESTRUCTURA CONS

(1 2 3)

(A (B C))

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.
Pgina 12

Apunte de Programacin Funcional III

Programacin

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 sexpresin 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 sexpresiones con quote devuelven siempre su propio valor. > 'A <return> 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
Pgina 13

Apunte de Programacin Funcional III

Programacin

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 > (EVAL X) Z funcin. > (EVAL (EVAL X)) 10 Clases de expresiones y como se evalan: Nmeros: su valor son ellos mismos (no hace falta QUOTE) Strings: su valor son ellos mismos (no hace falta QUOTE) Smbolos, o tomos simblicos: su valor es el valor asociado (bound) a ese tomo (no hace falta QUOTE, si queremos el valor asociado al tomo, pero hace falta QUOTE si queremos tratar el tomo como una constante) Llamadas a funcin (o expresiones funcionales) de la forma (fn arg1 arg2 ... argn) que se evalan (normalmente) as: 1. el valor asociado al primer elemento de la lista ha de ser la definicin de la funcin a aplicar, 2. evaluar (recursivamente) cada argumento, de izqda a derecha, 3. pasar los valores de los argumentos a la funcin a aplicar, 4. ejecutar la funcin con los argumentos recibidos, y 5. devolver el valor calculado por la funcin Por ejemplo, Evaluar 3 devuelve 3 Evaluar "Jane Doe" devuelve "Jane Doe" Evaluar x devuelve el valor asociado a x o "error" si x no tiene valor asociado (x unbound) Evaluar 'x devuelve x Evaluar (+ 1 2) devuelve 3 Evaluar (+ (* 3 5) 2) devuelve 17 ; los argumentos son evaluados antes de pasarlos a la ; tpico ciclo de evaluacin R-E-P

Pgina 14

Apunte de Programacin Funcional III

Programacin

COMANDOS FUNDAMENTALES
QUOTE FUNCION NUMERO DE ARGUMENTOS ARGUMENTOS RETORNA EJEMPLOS OPERACIN (QUOTE(ESTA ES UNA PRUEBA)) (QUOTE((ESTA)(ES UNA)PRUEBA)) (QUOTE HOLA) (QUOTE(()) RESULTADO (ESTA ES UNA PRUEBA) ((ESTA)(ES UNA)PRUEBA) HOLA () : : : : QUOTE 1 Un trmino cualquiera. El argumento.

Notar que QUOTE devuelve lo mismo que recibe; aparentemente esto no tiene mucho sentido, no obstante, la utilidad de este comando aparece cuando se utiliza, por ejemplo, el comando CAR entre parntesis, por ejemplo: (CAR(A B C)) En este caso, CAR buscar el primer elemento de la lista que genere la funcin A, pero como A no es una funcin (a menos que se defina como tal) generar un error. La sentencia correcta sera: (CAR(QUOTE(A B C)) Un error comn es escribir algo as: (CAR(QUOTE ERROR)) Ya que en este caso QUOTE retorna el tomo ERROR, y CAR debe recibir como argumento una lista (ver definicin siguiente).

CAR FUNCION NUMERO DE ARGUMENTOS ARGUMENTOS RETORNA : : : : CAR 1 Lista no vaca. El primer trmino de la lista.

Pgina 15

Apunte de Programacin Funcional III

Programacin

EJEMPLOS OPERACIN (CAR(QUOTE((ESTA) ES UNA PRUEBA))) (CAR(QUOTE((ESTA ES UNA PRUEBA)))) (CAR (QUOTE(()(ESTA ES UNA PRUEBA)))) (CAR(QUOTE (ESTA ES UNA PRUEBA))) RESULTADO (ESTA) (ESTA ES UNA PRUEBA) () (ESTA ES UNA PRUEBA)

Un error comn que se comete es algo como lo siguiente: CAR ((ESTO ES)(UN ERROR)) El primer parntesis es para indicar que se incluir el argumento de CAR, lo que no identifica a una lista, luego, en el argumento van dos listas en vez de una, que seran ESTO ES y UN ERROR. Esto se corrige haciendo la llamada: CAR(((ESTO NO ES)(UN ERROR))) Generalizando tenemos que cualquier comando que trabaje con una o ms listas como argumento debe encerrarlas entre parntesis, no as con los tomos (ver la aplicacin del comando QUOTE). CDR FUNCION NUMERO DE ARGUMENTOS ARGUMENTOS RETORNA : : : : CDR 1 Lista no vaca. El resto de la lista que queda despus de borrar el primer trmino.

EJEMPLOS OPERACIN
(CDR(QUOTE(ESTA ES UNA PRUEBA))) (CDR(QUOTE((ESTA ES)UNA PRUEBA))) (CDR(QUOTE((ESTA ES UNA PRUEBA)))) (CDR(QUOTE(()(ESTA ES UNA PRUEBA))))

RESULTADO
(ES UNA PRUEBA) (UNA PRUEBA) () ((ESTA ES UNA PRUEBA))

Las restricciones para CDR son iguales que para CAR. CONS FUNCION NUMERO DE ARGUMENTOS ARGUMENTOS RETORNA : : : : CONS 2 1. Cualquier trmino; 2. Una Lista cualquiera. Una lista, tal que su CAR es el primer argumento, y su CDR es el segundo
Pgina 16

Apunte de Programacin Funcional III

Programacin

argumento. EJEMPLOS OPERACIN


(CONS(QUOTE(ESTA ES)QUOTE(UNA PRUEBA))) (CONS(QUOTE ESTA)(QUOTE()))

RESULTADO
((ESTA ES)UNA PRUEBA) (ESTA)

ATOM FUNCION NUMERO DE ARGUMENTOS ARGUMENTOS RETORNA : : : : ATOM 1 Cualquier trmino. T si el argumento es un tomo; NIL en otro caso.

EJEMPLOS OPERACIN
(ATOM(QUOTE ABC54)) (ATOM(QUOTE(UN EJEMPLO))) ATOM(ABC54) ATOM(ESTO ES UN EJEMPLO)

RESULTADO
T NIL T NIL

EQ FUNCION NUMERO DE ARGUMENTOS ARGUMENTOS RETORNA EJEMPLOS OPERACIN


EQ(HOLA HOLA) EQ(HOLA B) (EQ(QUOTE HOLA)(QUOTE HOLA)) (EQ(QUOTE G)(QUOTE HOLA))

: : : :

EQ 2 Dos trminos. T si ambos tomos son iguales; NIL en otro caso.

RESULTADO
T NIL T NIL

NULL FUNCION NUMERO DE ARGUMENTOS : : NULL 1


Pgina 17

Apunte de Programacin Funcional III

Programacin

ARGUMENTOS RETORNA

: :

Cualquier trmino. T si el argumento es una lista vaca [()]; NIL en otro caso.

EJEMPLOS OPERACIN
NULL(()) NULL((())) NULL(ESTA ES UNA PRUEBA) (NULL(QUOTE()))

RESULTADO
T NIL NIL T

Tipos de datos bsicos |--- string Ej. "Jane Doe" | |--- nmero Ej. 27, 1.44 | |--- simbolo Ej. hungry, x

|--- tomo -| | expresin-S ---|--- lista Ej. (elem1 elem2 ... elemn) | (+ 2 3) | ((nombre ana)(edad 20)(padres (luis leo))) | |--- par con punto Ej. (edad . 20) Ligadura, o binding, es el proceso de asociar un valor con un tomo (simblico), incluyendo la reserva de memoria cuando es la primera vez que se referencia dicho tomo. No hace falta declarar el tipo de los tomos (aunque a veces viene bien hacerlo). Aunque los tomos no tenga tipo, sus valores asociados si que lo tienen. Inicialmente, todos los smbolos estn desligados (unbound), es decir, no tienen valor asociado. La ligadura se realiza con setq: (setq x 3) ; liga el valor 3 con el smbolo x (setq familia '(ana leo luis)) ; liga la lista (ana leo luis) con el ; smbolo familia Una lista es una secuencia de cero o ms elementos entre parntesis, sin incluir puntos. Ej., (a b c) es una lista de longitud 3, (a ((b)) c) es una lista de longitud 3, ((a b) c) es una lista de longitud 2, y () es una lista de longitud 0, llamada lista vacia o NIL.
Pgina 18

Apunte de Programacin Funcional III

Programacin

Operaciones sobre estructuras en forma de listas Funciones de acceso


Acceso a componentes de la lista first - tambin car devuelve el primer elemento (first '(one two three)) --> one (first '((one) (two) (three))) --> (one) rest - tambin cdr devuelve una lista conteniendo todos los elementos de la lista original y en el mismo orden, excepto el primero (rest '(one two three)) --> (two three) (rest '(one)) --> () o, lo que es lo mismo, NIL second, third, ..., nth, last

Funciones de construccin
cons - crea una nueva lista que tiene como primer elemento el primer argumento de cons, y como restantes elementos todos los de la lista que se pasa como segundo argumento. No-destructiva. (cons 'a '(b c)) --> (a b c) (cons '(a) '((b c))) --> ((a) (b c)) (cons 'a nil) --> (a) (cons 'a (cons 'b nil)) --> (a b) list - construye una lista con los elementos dados como parmetros (list 'a 'b '(c d)) --> (a b (c d)) quote - devuelve su argumento SIN EVALUARLO (se puede usar para tratar smbolos como constantes, en vez de como el valor del smbolo) Acta como la funcin identidad. (quote (a b c)) '(a b c) '(+ 1 2) 'orange --> --> --> --> (a b c) (a b c) (+ 1 2) orange

Pgina 19

Apunte de Programacin Funcional III

Programacin

append - construye una nueva lista juntando las listas dadas. (append '(a b) '(c d)) --> (a b c d)

Predicados Funciones que devuelven un valor Booleano: falso es NIL), y cierto es normalmente T o t, pero a veces cualquier otro valor distinto de NIL. atom - pregunta si su argumento es un tomo (atom 'a) (atom '(a)) --> T --> NIL

endp - tambin null, pregunta si una lista esta vacia (endp '(a)) (endp NIL) --> NIL --> T

equal - pregunta si dos expresiones-S "parecen iguales al ser imprimidas", es decir, se trata de una igualdad estructural de los valores comparados. Recomendacin: usar equal para comparar listas. (equal 'a 'a) --> T (equal '(a b) '(a b)) --> T (equal '(a b) '(a (b))) --> NIL

eq - pregunta si dos tomos son idnticos, o si dos expresiones-S son, en realidad, una nica expresin (es decir, no slo iguales sino almacenadas en la misma posicin de memoria). (eq 'a 'a) (eq '(a) '(a)) (setf x '(a)) (setf y x) (eq x y) --> T los tomos iguales son siempre nicos --> NIL

--> T

eql - pregunta si dos tomos, nmeros, caracteres o cadenas de carateres (strings) son iguales. Los nmeros, caracteres y strings no estn asociados con posiciones concretas de memoria, y por lo tanto, eq no es lo apropiado para ellos. Los nmeros han de tener el mismo tipo para ser considerados iguales con eql. El predicado eql se usa como valor por defecto en muchas funciones Lisp que llevan un parmetro opcional de tipo funcin predicado. (eql 'a 'a) --> T (eql 4 4) --> T (setf x (+ 2 2.3)) (eql 4.3 x) --> T
Pgina 20

Apunte de Programacin Funcional III

Programacin

= - pregunta si dos nmeros son iguales, sin necesidad de que tengan el mismo tipo para se considerado iguales (a diferencia de eql). (= 4 4.0) (= 'a 'a) --> T --> Error: arguments must be of type number

member - pregunta si una expresin-S aparece en el primer nivel de una lista. Utiliza eql como valor por defecto en el parmetro de palabra clave :test (que sirve para decidir si el elemento en cuestin es igual o no a alguno del primer nivel de la lista). (member (member (member (member (member 'b '(a b c)) '(a b) '(a b c)) 'b '(a (b) c)) '(a b) '(a (a b) c)) '(a b) '(a (a b) c) :test #'equal) --> --> --> --> --> (b c) NIL NIL NIL ((a b) c)

otros predicados: listp, null, numberp, zerop.

Operadores Lgicos
not, and, or

and y or utilizan evaluacin secuencial de sus argumentos de izqda. a derecha, y devuelven un valor tan pronto como el resultado est ya determinado, dejando sin evaluar los restantes argumentos. (setf lst '(a b c)) (and (member 'd lst) (member 'b lst)) --> NIL (and (member 'a lst) (member 'b lst)) --> (b c) (or (member 'a lst) (member 'd lst)) --> (a b c) Normalmente, en LISP no se declaran Las variables; la activacin de una variable ocurre dinmicamente cuando se hace la primera referencia a ella durante la ejecucin del programa. Adems, el tipo del valor almacenado en una variable puede variar durante la ejecucin. Por tanto, cuando una variable se utiliza en un contexto aritmtico, el programa debe asegurar que su valor actual es numrico. Si no, se producir un error en tiempo de ejecucin. Debe evitarse el uso de nombres de funciones del cuerpo del LISP para los nombres de variables, aunque no sean, estrictamente hablando "palabras reservadas". Por ejemplo, la legibilidad de un programa se hace ms difcil cuando se utiliza "and", not y "or" como nombres de variable en la siguiente expresin: (and , not, or)
Pgina 21

Apunte de Programacin Funcional III

Programacin

Debido a que las variables no se declaran, no puede suponerse que tengan ningn valor inicial preasignado. En algunos sistemas LISP, Las variables se inicializan todas automticamente a "nil" (nada), pero depender de esto no es normalmente una buena prctica de programacin.

FUNCIONES EN LISP
Las siguientes son las funciones que conforman el cuerpo de las funciones de LISP, slo se incluyen en la tabla las funciones que se presentan en la mayora de las versiones de LISP (incluyendo las vistas anteriormente).
abs car defun (de,df) function intern lessp (It) mapcon numberp prin1 read rplaca terpri and cdr dm(macro) gensym lambda expt maplist null prog remainder rplacd times (*) append close eq get length fix max open progn remob set cons apply cond equal getd list fixp min or put remprop setq atom assoc mapc eval go mapcan float nconc princ quote (') return subst map difference (-) explode greaterp(gt) mapcar floatp not print quotient (/) reverse plus (+)

Una funcin en LISP se escribe siempre de la siguiente forma general: (nombre argl arg2...) "Nombre" identifica a la funcin y "argl", "arg2", ... son los argumentos a los que se aplica la funcin. Por ejemplo: (+ 2 3) denota la suma 2 + 3, mientras que (list 2 3) denota la construccin de una lista cuyos elementos son 2 y 3, lo que se presenta como: (2 3) Las funciones pueden anidarse arbitrariamente, en cuyo caso se evalan de "dentro a fuera". Por tanto, (+ (* 2 3) 4)

Pgina 22

Apunte de Programacin Funcional III

Programacin

denota la suma de (2*3) y 4. Adems, una lista de funciones se evala de izquierda a derecha. Por ejemplo, (-(+23)(*34)) denota la diferencia de la suma 2 + 3 seguida del producto 3 * 4.

ARRAYS Y OTRAS ESTRUCTURAS DE DATOS ARRAYS


Un array puede declararse explcitamente en algunos dialectos del LISP usando la funcin "array", la cual tiene la siguiente forma: (ARRAY NOMBRE T TAMAO) "Nombre" identifica al array y "tamao" es una secuencia de enteros que identifica al nmero de elementos de cada dimensin. Por ejemplo, supongamos que A es un array de cinco elementos y B es un array de 5 x 4. Estos arrays pueden declararse como sigue:
(array A t 5) (array B t 5 4)

Una entrada a un array se referencia mediante una lista que contiene el nombre del array y una serie de subndices que identifican la posicin de la entrada en el array. Para este propsito, Las filas y las columnas se prenumeran desde 0 (como en el lenguaje C), en vez de desde 1 (como en la mayora de los dems lenguajes). Por tanto, la tercera entrada de A se referencia por (A 2) y el elemento de la cuarta fila y tercera columna de B se referencia por (B 3 2).

Para asignar un valor a una entrada de un array, se utiliza la siguiente funcin:


(store (nombre subndices) valor)

Por ejemplo, para almacenar el valor 0 en la entrada de la cuarta fila y tercera columna de B escribimos:
(store (B 3 2) 0)

En general, el valor almacenado puede especificar cualquier expresin en LISP y cada uno de los subndices pueden tambin ser cualquier expresin en LISP cuyo valor sea un entero en el rango adecuado. Por tanto, los arrays en LISP generalmente no tienen tipo, puesto que cada entrada puede ser diferente en estructura y tipo del resto.
Pgina 23

Apunte de Programacin Funcional III

Programacin

LISTA DE PROPIEDADES
Un mtodo mucho ms til de estructurar datos en una lista es mediante la llamada "lista de propiedades". Esta es una lista que tiene la siguiente forma general:
(p1 V1 p2 V2 .. pn Vn)

donde los p son tomos que denotan propiedades y las V son valores asociados a estas propiedades. Para ilustrar esto, supongamos que tenemos la informacin para un individuo clasificada de la siguiente forma:
(NOMBRE (ALLEN B TUCKER) SS# 275407437 SUELDQ BRUTO 25400 DIRECCION ((1800 BULL RUN) ALEXANDRIA VA 22200) )

Aqu hay cuatro propiedades, un nombre, un nmero de la Seguridad Social, un sueldo bruto y una direccin. Lo anterior corresponde a la definicin de una lista de propiedades (denominada por ejemplo PERSONA). Para obtener informacin de una lista de propiedades usamos la funcin "get" como sigue: (get nombre p) "Nombre" identifica a la lista y p identifica la propiedad cuyo valor se desea. Por ejemplo, para obtener el SS# de una PERSONA escribimos: (get PERSONA SS #) y el valor devuelto, para el anterior ejemplo, ser 275407437. Para reemplazar informacin en una lista de propiedades, se utiliza la funcin "put": (put nombre p v) "Nombre " identifica a la lista, p la propiedad cuyo valor va a ser reemplazado y v es el nuevo valor. Por ejemplo:
(put PERSONA SUELDO_BRUTO 30000)

Altera la propiedad SUELDO_BRUTO de PERSONA, de forma que su valor se hace 30000 en vez de 25400, como haba sido en el presente ejemplo. Finalmente, la funcin "remprop" quita una propiedad y su valor asociado de la lista.
Pgina 24

Apunte de Programacin Funcional III

Programacin

(remprop nombre p)

"Nombre" identifica la lista de propiedades afectada y p identifica la propiedad y el valor que han de quitarse. Por tanto, las listas de propiedades son muy tiles para definir lo que se conoce en otros lenguajes como "registros". Tpicamente una lista de propiedades representa un nodo en una lista mayor, enlazada de registros, todos con el mismo conjunto de propiedades. Esta lista mayor es conocida comnmente como un "archivo" en otros lenguajes. Por ejemplo, el registro PERSONA puesto anteriormente puede ser un nodo de una lista que contenga todas las personas empleadas en una determinada organizacin. Igualmente, puede definirse otra lista de propiedades especificas para una entrada en un catlogo de fechas de una librera y la lista de todas las entradas puede representar el propio catlogo.

FUNCIONES BSICAS
Anteriormente se dieron a conocer los comandos bsicos de LISP, en esta parte se darn a conocer ms a fondo las funciones clasificadas desde otro punto de vista.

Funciones aritmticas y asignacin de valor


Las funciones aritmticas bsicas del LISP son:

PLUS SETQ

DIFFERENCE SET

TIMES ADD1

QUOTIENT SUB1

Las cuales se abrevian en la mayora de los sistemas mediante los familiares signos +, -, * y /. Todas estas funciones tienen cero o ms operandos, o argumentos, y se escriben en la forma prefija como las otras funciones del LISP. Cuando se combinan para formar el equivalente a las expresiones aritmticas, estas funciones estn completamente puestas entre parntesis y, por tanto, no hay necesidad en LISP de definir ninguna precedencia jerrquica entre ellos. Para ilustrar esto, supongamos que H, I, N y X son variables en LISP. Las expresiones algebraicas mostradas en la parte de la izquierda (que es como se escribiran en otros lenguajes) se escriben en LISP como se muestra a la derecha: EXPRESION
H+2 H+2+I H+2*I SUM(X)/N

FORMA EN LISP
(+ H 2) (+(+H 2)I) (+H(*2 I)) (/(SUM X)N)
Pgina 25

Apunte de Programacin Funcional III

Programacin

Puesto que las formas en LISP estn completamente encerradas entre parntesis, su orden de evaluacin es siempre explcito. El segundo ejemplo supone que la evaluacin es de izquierda a derecha para las operaciones con la misma precedencia, mientras que el tercero supone que "*" tiene precedencia sobre "+" en las expresiones de la izquierda. El cuarto ejemplo ilustra la aplicacin de una funcin definida par el programador en el contexto de una expresin mayor. La asignacin del valor de una expresin a otra variable se realiza por la funcin "setq" o la funcin "set". Estas funciones tienen dos operandos:
(setq variable expresin) (set 'variable expresin)

En cualquiera de las dos, "variable" es el nombre de una variable que es el destino de la asignacin y "expresin" es una lista cuyo resultado se asignar a la variable. Por ejemplo, la funcin
(setq I (+ I 1))

Es equivalente a la familiar forma I := I + 1 en Pascal. Se evala primero la expresin de la derecha y el resultado se asigna a la variable I. En general, este resultado puede ser un tomo (un nmero o un smbolo) o una lista, como veremos en posteriores ejemplos. Las funciones unarias "addl" y "subl" se dan en LISP para simplificar la especificacin de la comn operacin de sumar o restar 1 del valor de una variable. Esta operacin se encuentra en todas Las aplicaciones de programacin y es especialmente frecuente en la programacin recursiva. Comilla (') y Evaluacin La comilla ('), la letra q en setq y la funcin "quote" se utilizan en LISP para distinguir explcitamente entre expresiones evaluadas. Esta distincin se necesita debido a la naturaleza dual de un smbolo en LISP en algunos contextos: su uso como un tem de dato y su uso como un nombre de variable. Si "E" denota cualquier expresin en LISP entonces su aparicin dentro de un programa implica normalmente que va a evaluarse inmediatamente y que el valor resultante se utilizar a continuacin. Sin embargo, la expresin (quote E) Que normalmente se abrevia como 'E, denote que E permanece por si misma y que no va a ser evaluada.

Pgina 26

Apunte de Programacin Funcional III

Programacin

Por ejemplo, consideremos las siguientes dos expresiones, en donde X se va a usar como variable (en la izquierda) y como un valor literal (en la derecha): COMO VARIABLE
((SETQ X 1) (SETQ Y X))

COMO LITERAL
((SETQ X 1) (SETQ Y 'X))

En la expresin de la izquierda, a las variables X e Y se les asigna a ambas el valor 1. En la expresin de la derecha, a X se le asigna el valor I y a Y se le asigna el valor (literal) X. El ltimo es, en efecto, una cadena de caracteres de longitud 1 o un tomo no numrico. Esto ayuda a explicar la diferencia entre "set" y "setq" del prrafo anterior. "Setq" es solo una forma conveniente de combinar "set" con un primer argumento con comilla. Es decir, el nombre de la variable de la izquierda de una asignacin no debe ser evaluado; designa una direccin en vez de un valor. Por tanto, las tres formas siguientes son equivalentes:
(setq X 1) (set,X 1) (set (quote X) 1)

En la prctica se prefiere normalmente la primera forma; la tercera es el precedente histrico de las otras dos.

Funciones De Manipulacin De Listas


La principal fuerza del LISP consiste en su potencia para manipular expresiones simblicas en vez de expresiones numricas. Para ilustrar esto, supongamos que tenemos una lista L compuesta de los nombres de nombres de lenguajes de programacin. Esto es, L = (pascal, fortran, cobol, pli) El valor de L puede ser asignado mediante la siguiente sentencia: (setq L '(pascal fortran cobol pli)) Observe aqu que la comilla (') fuerza a que se trate a la lista de lenguajes como un literal, en vez de como una coleccin de variables denominadas "pascal", "fortran", etc. Recuerde que, en general, una lista puede ser nada, un tomo o una serie de elementos entre parntesis (e1 e2 ... en). Las dos funciones bsicas vistas anteriormente, "car" y "cdr", se utilizan para dividir listas (es decir, sus representaciones subyacentes) en dos partes. "Car" define al primer elemento, e1, de una lista y "cdr" define a la lista
Pgina 27

Apunte de Programacin Funcional III

Programacin

que comprende el resto de los elementos (e2 ... en). En el caso especial en que n=1, la cdr se define como nada. Cuando la lista original es un tomo simple o nada, Las funciones car y cdr producen valores indefinidos y se producir un error en tiempo de ejecucin. (Algunas implementaciones son una excepcin y definen a car y cdr como nada en este caso especial. Este compromiso simplifica algunas veces la programacin de las situaciones "lmites", aunque sacrifica la consistencia y transportabilidad.) Ejemplos de aplicacin de estas funciones se pueden ver en la primera parte de este apunte. Algunas de las mltiples aplicaciones de las funciones car y cdr pueden abreviarse en LISP con los siguientes criterios: FUNCION
(CAR (CDR L)) (CDR(CAR L)) (CAR(CAR .. (CAR L).. ))) (CDR(CDR .. (CDR L).. )))

RESULTADO
(CADR L) (CDAR L) (CAA .. AR L) (CDD .. DR L)

Recuerden que todas estas aplicaciones son en el contexto de la construccin de funciones. Algunas implementaciones del LISP limitan el grado de anidamiento que puede abreviarse de esta forma. Sin embargo, para la mayora de las implementaciones pueden asumirse con seguridad al menos tres niveles. En contraste con la divisin de una lista en sus constituyentes est la funcin de construir una lista a partir de otras listas. Esto se realiza en LISP mediante las siguientes funciones. En esta descripcin, e1, e2, ..., son trminos cualesquiera.

FUNCION
(CONS e1 e2) (LIST e1 e2 .. en) (APPEND e1 e2 .. en)

SIGNIFICADO
YA VISTA. Construye una lista de la forma (e1 e2 .. en. Construye una lista de la forma (f1 f2 .. fn), donde cada f es el resultado de quitar los parntesis exteriores de cada e. Aqu los trminos e no pueden ser tomos.

Para ilustrar el uso de estas funciones, reconsideremos la lista L cuyo valor es (pascal fortran cobol pli). Si necesitamos construir una nueva lista M, cuyos elementos sean los de la lista L y los de la nueva lista (snobol apl lisp), podemos escribir lo siguiente: (setq M (list L '(snobol apl lisp))) El valor resultante de M es: ((pascal fortran cobol pli) (snobol apl lisp)) la cual es una lista de dos elementos, no de siete.

Pgina 28

Apunte de Programacin Funcional III

Programacin

Por otra parte, como ya vimos, "cons" tiene siempre dos argumentos. Por tanto, (cons 'snobol (cons 'apl (cons lisp nil))) construye la lista (snobol apl lisp) Por tanto, esta lista podra haberse construido de forma equivalente mediante la siguiente funcin: (list 'snobol 'apl 'lisp) "Append" es alga diferente de "list", en el sentido de que necesita que sus argumentos sean listas encerradas entre parntesis y ella quite dichos parntesis para construir el resultado. Por tanto, (append L '(snobol apl lisp)) da la lista de siete elementos: (pascal fortran cobol pli snobol apl lisp) la cual es estructuralmente distinta de la lista M formada en el anterior ejemplo . Finalmente, se aaden a este grupo de funciones las resumidas en la tabla siguiente.(Todas ellas usan como parmetros trminos, se debe verificar que parmetros son restringidos a solamente listas.) FUNCION
(RPLACA e1 e2) (RPLACD e1 e2) (SUBST e1 e2 e3) (REVERSE (e1 e2 .. en)) (LENGTH (e1 e2 .. en))

SIGNIFICADO
Reemplaza el car de e1 por e2. Reemplaza el cdr de e1 por e2. Reemplaza cada instancia de e2 en e3 por (el sustituto) e1. Invierte los elementos de la lista formando (en .. e2 e1). El nmero de trminos de la lista n.

En las funciones "rplaca" y "replacd", el argumento e1 debe denotar una lista puesta entre parntesis, para que las correspondientes car y cdr queden bien definidas. Igualmente, el argumento e3 de la funcin "subts" debe ser tambin una lista encerrada entre parntesis. Para ilustrar esto, supongamos de nuevo que tenemos las listas L y M, con los valores respectivos (pascal fortran cobol pli) y ((pascal fortran cobol pli)(snobol apl lisp)). Las siguientes expresiones conducen a los resultados mostrados a la derecha:
Pgina 29

Apunte de Programacin Funcional III

Programacin

EXPRESION
(RPLACA L 'MODULA) (RPLACD M 'PROLOG) (REVERSE (CARD M)) (SUBST 'ADA 'PLI L) (LENGTH L) (LENGTH M)

RESULTADO
(MODULA FORTRAN COBOL PLI) ((PASCAL FORTRAN COBOL PLI)PROLOG) (LISP APL SNOBOL) (PASCAL FORTRAN COBOL ADA) 4 2

Pgina 30

Apunte de Programacin Funcional III

Programacin

ESTRUCTURAS DE CONTROL
Las funciones en LISP pueden evaluarse en serie, condicional, iterativa o recursivamente. La recursividad se estudiar ms adelante, mientras que la evaluacin condicional e iterativa se tratan a continuacin. Detrs de la nocin de evaluacin condicional existe una coleccin de funciones en LISP, las cuales se clasifican como "predicados". Un predicado es cualquier funcin que cuando es evaluada devuelve el valor t (significando true) o nil (significando false). En otros lenguajes, estos predicados bsicos se definen normalmente va operadores "relacionales" y "booleanos". A continuacin se da una lista de los principales predicados del LISP, junto con sus significados. Aqu e, e1 y e2 son listas, x, x1 y x2 son expresiones aritmticas y p, p1, p2, ..., son predicados. PREDICADO
(PLUSP X) (MINUSP X) (ZEROP X) (LESSP x1 x2) (GREATERP x1 x2) (AND p1 p2 .. pn) (OR p1 p2 .. pn) (NOT p) (FIXP x) - (FLOATP x) (EQUAL e1 e2) (NUMBERP e) (ATOM e) (NULL e)

SIGNIFICADO
Devuelve t si x>0 y nil si no lo es. Devuelve t s x<0 y nil en los dems casos. Devuelve t si x=0 y nil en los otros casos. Devuelve t si x1<x2 y nil en los dems casos. Devuelve t si x1>x2 y nil en los dems casos. Devuelve t si todos los p1, p2, .., pn son t y nil en los otros casos. Devuelve t si uno o ms de los p1, p2, .., pn es t y nil en los dems casos. Devuelve t si p es nil y nil en los dems casos. Devuelve t si x es entero - punto flotante, respectivamente, y nil en los dems casos. Devuelve t si el valor de e1 es el mismo que el de e2 y nil en los otros casos. Devuelve t si e es un tomo numrico y nil en los otros casos. YA VISTA. YA VISTA.

Para ilustrar estas funciones, supongamos que la lista PUNTUACIONES tiene el valor (87.5, 89.5. 91.5) y la lista L tiene de nuevo el valor (pascal fortran cobol pli). La mayora de los ejemplos de la tabla siguiente utilizan estos valores para ilustrar los predicados del LISP. Algunos de estos ejemplos ilustran las situaciones "lmites" que surgen en el procesamiento de listas y la importancia de aplicar funciones a unos
Pgina 31

Apunte de Programacin Funcional III

Programacin

argumentos con el tipo correcto. Por ejemplo, los predicados "zerop", "plusp", "minusp", "lessp" y "greaterp" se aplican principalmente a expresiones que tienen valores numricos. PREDICADO
(PLUSP (CAR SCORES)) (MINUSP 3) (ZEROP(CAR L)) (LESSP (CAR SCORES) (CADR SCORES)) (GREATERP (CAR SCORES) 90) (AND (PLUSP(CAR SCORES)) (LESSP(CAR SCORES) 90) (EQUAL (CAR L) 'LISP) (OR (GREATERP(CAR SCORES)90) (GREATERP(CADR SCORES)90)) (NUMBERP(CAR L)) (NOT(NUMBERP(CAR L))) Nil T

RESULTADO
t Nil Indefinido t Nil T Nil Nil

Expresiones condicionales
Una expresin condicional en LISP es equivalente a una serie de sentencias if anidadas en lenguajes tipo Pascal. Tiene la siguiente forma general:
(cond (p1 e1) (p2 e2) . . . (pn en))

Cada uno de Los p1, ..., pn, denota un predicado y cada una de las e1, ..., en, la expresin que le corresponde, devolviendo la funcin como resultado la primera e de la secuencia, para la cual el correspondiente p es verdad y saltndose el resto.(Si ninguno de los p es verdad, la condicin cond devuelve nil.) Por tanto, en efecto, esto es lo mismo que el siguiente cdigo en Pascal:
if p1 then e1 else if p2 then e2 else .
Pgina 32

Apunte de Programacin Funcional III

Programacin

. . else if pn then en

En el caso de que queramos que la ltima alternativa en se evale en "todos Los dems casos" es decir, siempre que todos los p sean nil entonces ponemos pn a t en esta expresin condicional. Por ejemplo, supongamos que queremos calcular el IMPUESTO de una persona como el 25% de sus ingresos BRUTOS siempre que este ltimo exceda de 18.000 dlares y como el 22% de BRUTO en los dems casos. La siguiente expresin condicional realiza esto:
(cond ((greaterp BRUTO18000) (setq IMPUESTO (* 0.25BRUTO))) (t (setq IMPUESTO (* 0.22 BRUTO))))

Por tanto, esto es equivalente a la siguiente expresin en Pascal:

if BRUTO >18000 then IMPUESTO := .25 * BRUTO else IMPUESTO := .22 * BRUTO

Surge una confusin cuando alcanzamos el final de una expresin compleja en LISP, que se refiere sobre cuntos parntesis derechos deben aparecer al final para mantener el equilibrio necesario. Esta es una buena situacin para usar el corchete, ], para forzar un cierre mltiple sin tener que contar los parntesis izquierdos existentes. Por tanto, podemos escribir lo anterior como:
(cond ((greaterp BRUTO 18000) (setq IMPUESTO (* 0.25 BRUTO))) (t (setq IMPUESTO (* 0.22 BRUTO]

y todos los parntesis abiertos y no cerrados se cerrarn hasta el comienzo de la expresin condicional.

Iteracin
Aunque la recursividad es la forma primaria de expresar los procesos repetitivos en LISP, en algunas situaciones se prefiere la especificacin de bucles "iterativos". Para servir a esta necesidad, LISP contiene la "caracterstica prog", la cual, combinada con la funcin "go" (s, es la vieja sentencia goto!) permite que se especifique un tipo primitivo de bucle. Adems, algunas implementaciones del LISP contienen otras estructuras de control comparables a las sentencias while o for encontradas en lenguajes como el Pascal . La "caracterstica prog" tambin contiene una facilidad para definir "variables locales" dentro de la definicin de una funcin. A menos que se especifique as, todas las variables de un programa en LISP son (por defecto) de mbito global. La forma general de la caracterstica prog es la siguiente:
Pgina 33

Apunte de Programacin Funcional III

Programacin

(prog (locales) e~ e2... en) "Locales" es una lista que identifica a las variables locales de esta funcin. Cada una de Las e denote un trmino arbitrario en LISP y puede estar precedido opcionalmente por una "etiqueta". La etiqueta puede ser, a su vez, cualquier smbolo nico y sirve para dar un punto de bifurcacin a la funcin "go" que aparece en cualquier lugar entre estas expresiones. La funcin go tiene la siguiente forma general: (go etiqueta) "Etiqueta" es la etiqueta simblica que precede a alguna otra expresin dentro de la lista de expresiones. Por ejemplo, si queremos especificar la ejecucin repetida de una expresin e 10 veces, controlada por la variable (local) I, podemos escribir el siguiente segmento de programa:
(prog (I) (setq I 1) bucle (setq I (addl b) (cond ((lessp I 11) (go bucle))) )

Esto es equivalente al siguiente bucle en un lenguaje como el Pascal:


I:= 1; bucle: I := I + 1; if I < 11 then goto bucle

CRITERIOS DE ENTRADA-SALIDA
LISP es un lenguaje interactivo, por lo que las funciones de entrada-salida se realizan principalmente sobre el terminal. La mayora de las implementaciones permiten tambin el almacenamiento de archivos en memoria secundaria, pero esto es muy dependiente de la implementacin. En esta parte, trataremos slo con las funciones de entrada-salida orientadas a terminal. La funcin "read" no tiene argumentos y hace que se introduzca una lista por el terminal. Tiene la siguiente forma: (read) Cuando se encuentra esta funcin, el programa espera que el usuario introduzca una lista, la cual se convertir en el valor devuelto por esta funcin. Para asignar ese valor a una variable del programa, read puede combinarse dentro de una funcin "setq", como sigue:
Pgina 34

Apunte de Programacin Funcional III

Programacin

(setq X (read)) En efecto, esto dice "asignar a X el siguiente valor de entrada". Por tanto, si escribimos 14 en respuesta a la funcin read, 14 ser el valor de X. La forma ms directa de visualizar la salida sobre la pantalla de un terminal es usar la funcin "print", la cual tiene la siguiente forma: (print e) Aqu e puede ser cualquier expresin en LISP, y su valor se presentar sobre la pantalla como resultado de la ejecucin de esta funcin. En LISP existen tres variaciones disponibles de "print", las cuales se llaman "terpri", "prin1" y "princ". La expresin (terpri) se utiliza para saltar al comienzo de una nueva lnea. La expresin (prin1 e) es como (print e), excepto que no comienza en una nueva lnea. La expresin (princ e) se utiliza para suprimir las barras verticales, las cuales se utilizan para encerrar los tomos que contienen caracteres especiales (como "$" y "blanco", los cuales no se permiten normalmente dentro de un tomo). Por ejemplo, si quisiramos que un tomo tuviera el valor HURRA! tendramos que encerrarlo dentro de barras verticales, como las siguientes: | HURRA !| Si visualizramos esto usando print o prin1, Las barras verticales tambin apareceran.

SUBPROGRAMAS, FUNCIONES Y BIBLIOTECAS


Cada implementacin del LISP contiene una extensa biblioteca de funciones predefinidas, para el procesamiento de listas y cadenas. Los siguientes son ejemplos encontrados en la mayora de las implementaciones. x, xl, .., xn son expresiones numricas. FUNCION
(ABS x) (MAX x1 x2 .. xn)

SIGNIFICADO
Valor absoluto de x. Valor mximo de x1, x2, .. , xn.
Pgina 35

Apunte de Programacin Funcional III

Programacin

(MIN x1 x2 .. xn) (EXPT x)

Valor mnimo de x1, x2, .. , xn. Funcin exponencial de x, ex .

Adems, LISP contiene poderosas facilidades para que el programador extienda el lenguaje definiendo funciones adicionales. Esta caracterstica tiene la siguiente forma general: (defun nombre (parmetros) e1 e2 ... en) "Nombre" identifica a la funcin, "parmetros" es una lista de smbolos atmicos que son los parmetros de la funcin y e1, e2, ..., en son las expresiones que definen la funcin. Tres de tales funciones, llamadas "sum", "cont" y "media", se han definido en el programa anterior. Las primeras dos tienen el parmetro x, mientras que la tercera no tiene parmetros y sirve como el programa principal. Las diferentes implementaciones del LISP contienen algunas diferencias sintcticas para la definicin de funciones. Algunas de estas variaciones respecto a la forma dada son las siguientes: (def nombre) (lambda (parmetros) e, e2 ... en)) (de nombre (parmetros) e, e2 ... en)

nombre: (lambda (parmetros) el e2 ... en)

La palabra "lambda" proviene de las primeras versiones del LISP, las cuales tenan una sintaxis ms parecida a la notacin de Church, de la que proviene el LISP. Pero todas estas versiones sirven al mismo propsito y ninguna es intrnsecamente superior a las otras. Usamos la forma original a lo largo de este manual, suponiendo que el lector podr asimilar las otras variaciones si es necesario. En el corazn de la definicin de funcin est la idea de la recursividad. Esto es al LISP como la "sentencia WHILE" al C. La definicin de funciones recursivas proviene directamente de las matemticas, como se ilustra en la siguiente definicin de la funcin factorial.
factorial (n) = 1 si n <= 1 = n * factorial(n-1) si n>1

Como es evidente, la definicin del factorial se basa en si misma para poder calcular el factorial de cualquier valor particular de n > 1. Por ejemplo, el factorial de 4 depende de los anteriores clculos del factorial de 3, y as sucesivamente. El proceso termina cuando se llega al factorial de 1, que es cuando puede completarse cada uno de los otros clculos dependientes de los anteriores. Esta definicin de funcin puede escribirse
Pgina 36

Apunte de Programacin Funcional III

Programacin

directamente en LISP, aprovechndose del hecho de que una funcin puede llamarse a si misma.
(defun fact (n) (cond ((lessp n 2) 1) (t (* n (fact (sub I n)]

Hemos identificado al parmetro n y definido "fact" mediante una expresin condicional que es equivalente a la siguiente expresin en un lenguaje tipo Pascal:
if n<2then 1 else n * fact (n - 1)

En un caso, el resultado devuelto ser 1, mientras que en los otros el resultado ser el clculo (* n (fact (subl n))), el cual llamar a la propia funcin. Para llamar as a una funcin, se utiliza la misma forma que para las funciones dadas par el LISP: (nombre argl arg2...) "Nombre" identifica a la funcin y "argl arg2..." es una serie de expresiones, correspondiente a los parmetros de la definicin de la funcin. Por tanto, para calcular el factorial de 4 escribimos "(fact 4)" El resultado de la evaluacin dar la siguiente expresin (* 4 (fact 3)) que, una vez evaluada, dar lugar a la expresin (* 3 (fact 2)) y finalmente se llegar a lo siguiente: (* 2 (fact 1)) Ahora, cuatro llamadas diferentes de "fact" estn activas y la ltima devuelve finalmente el valor 1. Esto permite que se evale la expresin (*2 1) y que el resultado 2 se pose a la expresin (* 3 2), y as sucesivamente hasta que se completan todas las activaciones. Otras dos formas sencillas de definiciones recursivas aparecen en el programa del comienzo, una para la funcin "sum" y la otra para la funcin "cont". Cada una de ellas combina las funciones primitivas de procesamiento de listas "car" y "cdr" con los clculos numricos, para llegar al resultado deseado.
Pgina 37

Apunte de Programacin Funcional III

Programacin

Aqu la recursividad es esencial porque las longitudes de las listas varan normalmente de una ejecucin a la siguiente. Un examen de la funcin sum con el argumento (87.5, 89.5, 91.5, 93.5) muestra que, puesto que este argumento ni es "nulo" ni es un tomo, la llamada recursiva (+ (car x) (sum (cdr x))) se evala a continuacin.

Funciones, Variables Locales Y La Caracterstica Program


Aunque la recursividad es el dispositivo primario para definir funciones en LISP, en algunas ocasiones es necesaria la iteracin. Adems, la mayora de las funciones requieren el uso de variables locales para disponer de un almacenamiento temporal mientras realizan sus tareas. Cualquiera de estos dos requerimientos fuerzan al uso de la "caracterstica prog" dentro de la definicin de una funcin como sigue:
(defun nombre (parmetros) (prog locales) e1 e2 ... en ))

La secuencia de expresiones e1, e2, ..., en puede incluir ahora a la funcin go, mientras que "parmetros" y "locales" tienen el mismo significado que se dio originalmente. En muchos casos, la naturaleza de la funcin fuerza la denotacin explcita del resultado que ha de devolverse en la llamada. Esto se activa mediante la funcin "return", la cual tiene la siguiente forma dentro de una definicin de funcin:
(return expresin)

"Expresin" es el valor que ha de devolverse a la expresin llamadora y la devolucin del control se produce en cuanto se encuentra esta funcin. Para ilustrar esto, se muestra a continuacin una interpretacin iterativa de la funcin factorial:
(defun fact (n) (prog (i f) (setq f 1) (setq i 1) bucle (cond ((greaterp i n) (return f)) (t ((setq f (* f i)) (setq i (addl i)) (go bucle)]

Aqu tenemos las variables locales f e i inicializadas ambas a 1. La sentencia condicional etiquetada con "bucle" se repite hasta que i > n,
Pgina 38

Apunte de Programacin Funcional III

Programacin

devolvindose en ese momento el valor resultante de f. Si no, se realizan los clculos f:=f*i yi:=i+ I y se repite el test para i > n. Aunque este ejemplo ilustra el uso de la funcin "return", la caracterstica prog y la iteracin sirve tambin para subrayar la superioridad expresiva de la recursividad como dispositivo descriptivo del LISP.

ESCRITURA DE PROGRAMAS EN LISP


Un programa en LISP se ejecuta normalmente interpretativa e interactivamente. En su forma ms sencilla, un programa o una funcin se representa como una expresin completamente puesta entre parntesis con todos los operadores en la forma prefija. Todas las variables tienen valores tomos o listas. El programa que se muestra a continuacin es un programa en LISP que calcula y visualiza la media de una lista de nmeros de entrada. (Aunque este problema concreto es la anttesis de los problemas a los que se aplica normalmente el LISP, lo usaremos para ilustrar la sintaxis y desarrollar una base para la enseanza del lenguaje.) Por ejemplo, si la entrada es la lista: (85.5 87.5 89.5 91.5) Entonces el resultado presentado ser el valor 88.5. La variable x se utiliza para almacenar la lista de entrada y la variable n se utiliza para determinar cuntos valores hay. La variable med contiene al final la media calculada.
(defun sum (x) ;calcula la suma de una lista x (cond ((null x) O) ((atom x) x) (t (+ (car x) (sum (cdr x)] (defun cont (x) ; cuenta el nmero de valores de x (cond ((null x) O) ((atom x) 1) (t (addl (cont (cdr x)] (defun media () ; el programa principal comienza aqu (print 'introducir la lista a promediar') (setq x (read)) (setq n (count x)) (setq med (/ (sum x) n))
Pgina 39

Apunte de Programacin Funcional III

Programacin

(princ "la media es = ) (print med)]

El programa est compuesto de tres funciones del LISP, cada una indicada por la cabecera "defun" (abreviacin de "define function). La primera funcin "sum" calcula la suma aritmtica de los elementos de la lista x. La segunda, "cont", calcula el nmero de valores de la lista. La tercera funcin, "media", es el programa principal y controla la entrada (usando "read), el clculo de la media "med" y la salida (usando "print"). Los comentarios en LISP comienzan con el delimitador especial punto y coma (;) y continan hasta el final de la lnea. Las variables estn normalmente sin declarar y tienen un mbito global. Tambin pueden especificarse variables acotadas, las cuales son locales a una funcin. Los bucles en LISP se dan normalmente mediante la recursividad en vez de mediante la iteracin. Entonces, par ejemplo, el clculo de sum se hace mediante la siguiente definicin recursiva: Si la lista est vaca (es decir, "nula"), la suma es 0. Si la lista tiene una entrada, la suma es esa entrada. Si la lista tiene ms de una entrada, la suma es el resultado de aadir la primera entrada (es decir, el "car") y la suma de la lista compuesta de las restantes entradas (es decir, la "cdr"). Por tanto, si la lista es (l 2 3 ), entonces su suma es 1 ms la suma de la lista (2 3), y as sucesivamente. La estructura sintctica del LISP es muy sencilla. El programa es una expresin completamente puesta entre parntesis, en la cual todas las funciones aparecen como operadores prefijos. En algunas implementaciones del LISP hay dos clases de parntesis, () y []. Los corchetes se utilizan para especificar cierres mltiples. El corchete derecho, ], puede usarse al final de una definicin de funcin para cerrar efectivamente todos los parntesis izquierdos, (, que le precedan. Esto evita la necesidad de contar y explcitamente equilibrar los parntesis derechos en muchos casos. Usaremos ms adelante este criterio. Finalmente, observe que no hay una diferencia fundamental entre la estructura de los programas en LISP y sus datos. Esta caracterstica conduce a una fuerte facilidad inherente para que los programas manipulen a otros programas, como veremos. Tambin esto permite una uniformidad bsica de las expresiones no encontradas en otros lenguajes. Por tanto, este breve ejemplo contiene los condimentos bsicos de la programacin en LISP.

OTRAS CARACTERISTICAS
Entre las restantes caractersticas del LISP, la facilidad de definicin de macro y las funciones "eval", "mapcar", "mapcan" y "apply" son, quiz, las ms importantes.

Pgina 40

Apunte de Programacin Funcional III

Programacin

Definicin y expansin de macros


La nocin de "macro", en general, es la de que una funcin puede automticamente reinstanciarse o "generarse" en lnea dentro del texto de un programa siempre que se necesite. Las macros han sido una importante herramienta de los programadores de sistemas durante mucho tiempo, pero su potencia se ha utilizado principalmente a nivel del lenguaje ensamblador. En LISP, las macros ofrecen una alternativa a las funciones para el mismo propsito. Una definicin de macro en LISP tiene la siguiente forma bsica: (defun nombre macro (parmetro) e1 e2 ... en) (Algunas implementaciones requieren una sintaxis alga diferente a sta, usando "dm" para la definicin de macro en vez de "defun" y "macro". El lector debe ser capaz de asimilar estas diferencias sintcticas.) "Nombre" identifica a la macro y "parmetro" es un valor que ser sustituido en las expresiones e1, e2, ... y en cuando se expanda la macro. El resultado de la expansin se ejecuta entonces en lnea. Una macro se llama igual que si fuera una funcin: (nombre argumentos) Pero la accin que tiene lugar no es una transferencia de control, como con las funciones, sino una generacin en lnea de texto del programa, el cual se ejecuta a continuacin. Para ilustrar esto, supongamos que queremos definir una macro que simule una sentencia while de otro lenguaje; esto es, (while X Y) ejecutara repetidamente Y hasta que X se hace 0. La "forma" de este bucle ser como sigue:
(prog () bucle (cond ((greaterp X 0) (Y (setq X (subl X)) (go bucle)))))

Esto es, si X > 0 entonces se ejecuta Y, se decrementa X en 1 y se repite el bucle. Puede definirse entonces una macro llamada "while" con la anterior configuracin como su cuerpo y representando el parmetro P toda la llamada a la macro (while X Y), como sigue:

(defun while macro (P)


Pgina 41

Apunte de Programacin Funcional III

Programacin

(subst (cadr P) 'X) ( subst (caddr P) 'Y) (prog () bucle (cond ((greaterp X 0) (Y ( setq X (subl X)) (go bucle)))))

Las dos funciones "subst" reemplazan al primer y segundo argumento de la llamada para X en el cuerpo de la definicin de la macro y luego se ejecuta el cuerpo. Por ejemplo, la siguiente llamada a macro repite el clculo del factorial F de N, mientras el valor de I es mayor que 0. (while I (setq F (* F D)) La expansin de esta llamada a macro, cuando es ejecutada, aparece a continuacin
(prog () bucle (cond ((greaterp I 0) ((setq F (* F b) (setq I (subl b) (go bucle)))))

Observe que (cadr P) es I en este caso y (caddr P) es (setq F (* F D). Este cdigo puede compararse con la versin iterativa de la funcin factorial presentada anteriormente.

Eval, Mapcar Y Aaply


La macro es un dispositivo para la suspensin temporal de la ejecucin de un programa, mientras se generan o transforman automticamente ciertas sentencias del programa. Lo mismo puede hacerse de una forma ms modesta usando la funcin "eval". Eval es la funcin opuesta de "quote", en el siguiente sentido. Si una variable X tiene el valor (A B), entonces la expresin (list X 'C) da el resultado (A B C). Sin embargo, la expresin (list 'X 'C) fuerza a que X se trate como un literal sin valor, en vez de como una variable, por lo que el resultado es (X C). Cuando se aplica eval a una expresin con comilla, anula el efecto de la comilla y fuerza a que se evale la expresin. Por tanto, continuando con el ejemplo anterior: (list (eval 'X) 'C)

Pgina 42

Apunte de Programacin Funcional III

Programacin

da de nuevo el resultado (A B C), puesto que (eval 'X) es equivalente a la expresin X en este contexto. La funcin "mapcar" tiene la siguiente forma general: (mapcar 'nombre 'args) "Nombre" es el nombre de alguna funcin y "args" es una lista de argumentos para los cuales y en orden debe aplicarse repetidamente la funcin especificada. Por ejemplo: (mapcar 'subl '(1 2 3)) da la expresin resultante: ((subl 1) (subl 2) (subl 3)) Esto es, la funcin es copiada para los elementos de la lista, dando como resultado una lista de aplicaciones de la misma funcin a diferentes argumentos. La funcin "apply" se utiliza para que se aplique repetidamente una funcin a una lista de argumentos, en vez de slo una vez a los distintos argumentos requeridos por la funcin. Su forma general es: (apply funcin (argumentos)) Por ejemplo, supongamos que queremos calcular la suma de los elementos de la lista ( 1 2 3). Podemos hacer esto escribiendo (apply ' + (I 2 3)) lo cual es equivalente a la evaluacin anidada (+ (+ 1 2) 3). Observe que (+ (1 2 3)) no funcionara, puesto que "+" es estrictamente una funcin de argumentos numricos.

Pgina 43

Apunte de Programacin Funcional III

Programacin

UN EJEMPLO DE APLICACIN DE LISP


"El problema de los misioneros y los canbales"

La principal estructura de datos para este problema es una cola con todos los caminos desde el estado inicial al estado final. Un "estado" en este contexto es un registro del nmero de misioneros y canbales que estn en coda orilla y un conmutador que dice si la barca est en la orilla izquierda o en la derecha. Cada estado est compuesto de una lista de dos tripletas como sigue: Orilla izquierda ( (M C B) Orilla derecha (M C B) )

M y C son el nmero de misioneros y el nmero de canbales sobre coda orilla y B es 1 0, dependiendo de si la barca est o no en una orilla particular. Por tanto, el estado original del juego es el siguiente: ((331) (000)) con todos los misioneros, canbales y la barca en la orilla izquierda. El estado final deseado se representa como: ((000) (331)) Conforme progresa el juego, crece la cola cada vez que se encuentra una transicin de estados posibles, y en cada etapa se realiza una comprobacin para ver que no ha tenido lugar canibalismo como resultado de la transicin realizada. El nombre de esta cola en el programa es q. Un movimiento, denotado por la variable "movimiento", se da tambin mediante una tripleta, la cual contiene el nmero de misioneros en la barca, el nmero de canbales en la barca y la constante 1 denotando a la propia barca. Por tanto, por ejemplo, (111) denota a un movimiento en el que la barca contiene un misionero y un canbal. La variable "historia" contiene la historia de todos los estados de la orilla izquierda, Los cuales han sido ya tratados anteriormente en el juego. La variable "posible" es una lista de constantes que contiene todas las posibles alternativas para "un movimiento"; esto es, todas las posibles combinaciones de misioneros y canbales que pueden cruzar el ro de una vez. El programa consta de una funcin principal "myc" y varias funciones auxiliares "comido", "expandir", "movcorrecto", "mover" y "presentar". Cada una de estas funciones se documenta brevemente en el texto del programa.

Pgina 44

Apunte de Programacin Funcional III

Programacin

PROGRAMA
(defun myc () (prog (q historia) ; inicializa la cola y los posibles movimientos (setq posibles '((O 2 1)(0 1 1)(1 1 1)(1 0 1)(2 0 1)))) (setq q (list (list (list '(3 3 1) '(O O O))))) repeat ; este bucle se repite hasta que est vaca la orilla izquierda (cond ((equal (caaar q) '(O O O)) (return (display (reverse (car q))))) ; desecha un camino si da lugar a canibalismo ; o representa un bucle ((or (comido (caar q)) (member (casar q) historia)) (setq q (cdr q)) (go repeat)) ) ; ahora aade este estado a la historia y pasa ; al siguiente estado (setq historia (cons (caar q) historia)) (setq q (append (expandir (car q) posibles) (cdr q))) (go repeat) ] (defun comido (estado) ; esta funcin comprueba si existe canibalismo examinando ; la orilla izquierda (car estado). Si all M es 1 0 2 ; y M <>C, entonces hay canibalismo en una u otra orilla. ; Si no, no hay en ninguna. (and (or (equal (caar estado) 1) (equal (caar estado) 2)) (not (equal (caar estado) (cadar estado))) ] (defun expandir (caminos posibles) ; esta funcin desarrolla todos los posibles movimientos ; a partir del estado actual. (cond ((null posibles) nil) ((movcorrecto (car mover) (car posibles)) (cons (cons (camino (mover (car camino) (car posibles)) camino) (expandir camino (cdr posibles)))) (t (expandir camino (cdr posibles))) (defun movcorrecto (estado unmovimiento) ; aqu se resta el nmero de misioneros y canbales ; que hay en el bote del nmero que queda ; en la orilla actual, para asegurarse que no se cogen ; ms de los que hay.
Pgina 45

Apunte de Programacin Funcional III

Programacin

(cond ((zerop (caddar estado)) ; ve si bate en la derecha (restatodo (cadr estado) unmovimiento)) (t (restatodo (car estado) unmovimiento)) (defun restatodo (triple unmovimiento) ; esta funcin resta loa tres nmeros de un movimiento ; del bate del contenido de una orilla y devuelve ; nil si cualquiera de Las diferencias es <0 (not (minusp (apply 'min (mapcar ' - triple unmovimiento) ] (defun mover (estado unmovimiento) ; esta funcin realiza un movimiento restando ; los nmeros de un movimiento del bote de una orilla ; y sumndolos a la otra. (cond ((zerop (caddar estado)) ; comprueba si bote en la derecha (list (mapcar '+ (car estado) unmovimiento) (mapcar '- (cadr estado) unmovimiento))) (t (list (mapcar '- (car estado) unmovimiento) (mapcar '+ (cadr estado) unmovimiento))) ] (defun display (path) ; esta funcin presenta la solucin resultante (con ((null camino) 'end) (t (print (car camino)) (terpri) (display (cdr camino))

Pgina 46

Anda mungkin juga menyukai