Intro Common Lisp 2012

Post on 11-Aug-2015

87 views 2 download

Transcript of Intro Common Lisp 2012

Introducción aCommon Lisp

Elaborado por:

Dr. Sergio Luis Castillo Valerio

Este presentación puede reproducirse libremente conservando estos derechos de autor.

Descripción General Lisp = List Processing. Inventado por John McCarthy a finales de los 50’s. Adecuado para IA por su habilidad para el

procesamiento eficiente de información simbólica. Lenguaje con sintaxis simple, casi nulo manejo de

tipos y administración dinámica de memoria.

Common Lisp Existen varios dialectos de Lisp: Franzlisp, Interlisp,

Maclisp, Qlisp, Scheme, etc. Common Lisp es un intento por estandarizar el

lenguaje y hacerlo más portable y fácil de mantener. Por tanto, Common Lisp es el lenguaje a aprender. En adelante, al referirnos a Lisp, nos estaremos

refiriendo a Common Lisp.

Bloques básicos (1) Los bloques de construcción básicos de Lisp son:

– El átomo.– La lista.– La cadena de caracteres (string).

Estos 3 son los únicos objetos válidos en Lisp. Son llamados expresiones simbólicas o expresiones-

s.

Bloques básicos (2) Átomo

– Todo número o secuencia de caracteres es un átomo. Lista

– Es una secuencia de átomos y/o otras listas encerradas entre paréntesis y separadas por uno o más espacios.

Cadena de caracteres:– Grupo de caracteres encerrados entre dobles

comillas (“ “).

Ejemplos de bloques básicos Algunos átomos válidos:

– esto-es-un-atomo - 345– bloque#1 - *var*

Algunas listas válidas:– (1 2 3) - (a (a b) c d)– (hijo Luis (José Susana)) - ()

Algunas cadenas de caracteres válidas:– “Hoy es lunes” - “a b c d e”– “1 2 3 4” - “teclea la fecha:”

Expresiones-s Toda expresión-s es potencialmente un programa

válido en Lisp.

Los programas pueden ser interpretados o compilados.

En un intérprete de Lisp, el programa fuente se examina en un lazo repetitivo llamado lazo lee-evalúa-imprime (read-evaluate-print loop).

Notación prefija (1) Lisp utiliza notación prefija. Por ejemplo:

– >(+ 5 6 7)– >18– >

El prompt “>” indica que el intérprete está listo para leer.

El símbolo + es una función y 5, 6 y 7 son sus argumentos.

Notación prefija (2) El nombre de la función y sus argumentos se

encierran entre paréntesis para indicar al intérprete que debe evaluarla.

El lazo lee-evalúa-imprime del intérprete, lee la función con sus argumentos, la evalúa e imprime el valor que la función regresa (18, en el ejemplo anterior).

Después, imprime otra vez el prompt para indicar que está listo para la siguiente lectura.

Funciones numéricas Las funciones numéricas básicas son:

– +, -, * y / (suma, resta, multiplicación y división)

Los argumentos pueden ser enteros o números reales (de punto flotante).

– + y * toman 0 o más argumentos.– - y / toman al menos 1 argumento.

Ejemplos:– (+ 3 5 8 4)- (- 10 12)– (* 2 3 4) - (/ 25 2)

Constantes importantes Lisp trata de avaluar todo, incluyendo los argumentos

de una función.

Existen 3 tipos de elementos que son especiales porque siempre regresan su propio valor:

– Los números.– La letra t (para verdadero).– Nil (para falso). (Nil: palabra sueca para 0 o nada)

• Nil es el único objeto de Lisp que es a la vez un átomo y una lista (la lista vacía).

Evaluación de funciones (1) Cada función se evalúa en el orden en que ocurre

dentro de los paréntesis de izquierda a derecha. Por ejemplo.

● > (+ (* (/ 9 5) 50) 32) → 122

La función a evaluar primero es la suma, pero su primer argumento es una multiplicación.

Por tanto, se debe evaluar primero la multiplicación.

Evaluación de funciones (2) Pero a su vez, el primer argumento de la

multiplicación es una división, por tanto, es necesario evaluar primero esta división.

La división regresa el valor 1.8 a la multiplicación, para dar (* 1.8 50).

La multiplicación regresa el valor 90 a la suma para dar (+ 90 32), que al ser evaluada regresa el

valor 122.

Funciones lógicas (1) Las funciones lógicas básicas son NOT, AND y OR.• NOT es la más simple, toma un solo argumento y

regresa T si el argumento se evalúa como nil y NIL si el argumento es diferente de nil.

• (not (= 0 5)) → T• (not (< 4 5)) → NIL

Función lógica AND La función AND toma cualquier número de

argumentos que se evalúan de izquierda a derecha. Si todos los argumentos evalúan diferente de nil, AND regresa el valor del último argumento, de otra manera regresa NIL.

• (and (< 4 5) 1) → 1• (and 5 3 (= 3 2)) → NIL

Función lógica OR Los argumentos del OR se evalúan de izquierda a

derecha hasta que uno de ellos evalúa diferente de nil, en cuyo caso regresa ese valor; de otra manera regresa NIL.

• (or (< 4 3) (> 4 3)) → T• (or (< 3 4) 7 5) → 7

Marca de Acotación (quotation mark) Algunas veces se quiere que un átomo o una lista

sea considerada como un dato y no como una función que debe evaluarse.

Para esto, se utiliza la marca de acotación (quotation mark).

Por ejemplo:– '(a b c d) - '(+ 3 4 5)– En el primer caso se considera a la lista como el

conjunto de datos a, b c y d, y no como la función a con argumentos b, c y d.

Nota: El apóstrofe ' equivale a la forma quote

Asignación de valores a variables Variable: Un átomo no numérico, esto es, un átomo

simbólico, al que pueden asignarse o ligarse valores cambiantes.

Función setq– Asigna o liga una variable con un valor.– Toma 2 argumentos:

● (setq variable valor)– Por ejemplo:

● (setq x 10) ; x = 10● (setq lst1 ‘(a b c)) ;lst1=(a b c)

Asignación con setf

• setf nos permite asignar valores a varias variables. Sintáxis:• (setf var1 val1 var2 val2 ... varn valn)

Ejemplo:• (setf a 10 b 15 c 12) ;a=10,b=15,c=12

Manipulación de listas (1) Algunas funciones básicas para el manejo de listas son:

● (first lista) o (car lista): Regresa el primer átomo de lista● (rest lista) o (cdr lista): Regresa el resto de lista

Por ejemplo:– (setq lst1 ‘(a b c d)) → (a b c d) ; crea lista– (first lst1) → a ; primer elemento– (car lst1) → a– (rest lst1) → (b c d) ; resto de la lista– (cdr lst1) → (b c d)

Manipulación de listas (2) Otras funciones para el manejo de listas son:

● first, second, third, fourth, fifth, sixth, seventh, eighth, ninth y tenth.

Por ejemplo:– (setq lst1 ‘(a b c d)) → (a b c d) ; crea lista– (first lst1) → a ; primer elemento– (second lst1) → b ; segundo elemento– (fourth lst1) → d ; cuarto elemento

Manipulación de listas (2) Otras funciones para el manejo de listas son:

● (nth indice lista)

Por ejemplo:– (setq lst1 ‘(a b c d)) → (a b c d) ; crea lista– (nth 0 lst1) → a ; elemento cero– (nth 1 lst1) → b ; elemento uno– (nth 3 lst1) → d ; elemento tres

Construcción de listas(1) Otra función para el manejo de listas:

– (cons elemento lista) cons utiliza 2 argumentos. Construye una nueva lista haciendo a elemento el

primer miembro de lista. Por ejemplo:

– (cons ‘a ‘(b c)) → (a b c)– (cons (* 2 3) ‘(1 2 3)) → (6 1 2 3)

Construcción de listas(2) Otra función para el manejo de listas:

– (list átomo1 átomo2 ... átomo_n) Construye una lista con miembros átomo1,

átomo2, ..., átomo_n Toma cualquier número de argumentos.

– (list ‘a ‘b ‘c ‘d) → (a b c d)– (list ‘a ‘(b c d)) → (a (b c d))– (list (+ 2 3) ‘a ‘b) → (5 a b)

Funciones en general La sintaxis para llamar a una función es:

– (nombre_función arg1 arg2 ...) Al llamarse a un función los argumentos se evalúan

de izquierda a derecha (a menos que haya un marca de acotación).

Entonces la función se ejecuta usando los valores evaluados de sus argumentos.

Ejemplo:– (cons (car ‘(a 2 )) (cdr ‘(2 b c ))) → (a b

c)

Más funciones para listas (1) append: Unión de 2 o más listas en una:

– (append ‘(a) ‘(b c)) → (a b c) last: Regresa una lista con el último elemento:

– (last ‘(a b c d)) → (d)– (last ‘(a b c d) 2) → (c d)

butlast: Regresa la lista sin el último elemento– (butlast '(a b c d e)) → (a b c d)– (butlast '(a b c d e) 2) → (a b c)

Más funciones para listas (2) reverse: Regresa la lista en orden inverso:

– (reverse ‘(a (b c) d e)) → (e d (b c) a) sort: Ordenamiento de listas:

– (sort ‘(2 4 1 5 3) #’<) → (1 2 3 4 5)– (sort ‘(2 4 1 5 3) #’>) → (5 4 3 2 1)– (sort '(b c a) 'string-lessp) → (a b c)– (sort '(b c a) 'string-greaterp)→(c b a)

position: Posición dentro de lista– (position ‘d ‘(a b c d e f))→ 3

Más funciones para listas (3) member: Regresa el resto de la lista a partir de

primer argumento:– (member ‘b ‘(a b c d)) → (b c d)

set-difference: Regresa los elementos que resultan de “restar” dos listas.

– (set-difference '(a b c d) '(a c)) → (b d)

length: Regresa el número de elementos de nivel superior que hay en una lista.

– (length '(a b (c d))) → 3

Más funciones para listas (4) remove: Elimina un elemento de una lista: (remove 100 '(1 2 100 3)) → (1 2 3) union: Toma 2 listas como conjuntos y regresa la

unión de esos 2 conjuntos:– (union '(a b c d) '(a c e)) → (b d a c e)

intersection: Regresa la intersección de 2 listas consideradas como conjuntos:

– (intersection '(a b c) '(b c d))→(b c)

Funciones matemáticas de Lisp mod: Función Módulo:

– (mod 26 3) → 2– (mod -25 4) → 3

rem: Función Residuo (remainder):– (rem 26 3) → 2– (rem -25 4) → -1

abs: Valor absoluto:– (abs -3.5) → 3.5

Otras funciones matemáticas (2) sqrt: Raíz cuadrada (square root):

– (sqrt 25) → 5 max y min: Máximo y mínimo:

– (max 3 5 9 3 1) → 9 – (min 3 5 9 3 1) → 1

expt: Exponenciación– (expt 2 3) → 8 (23)

exp: en– (exp 1) → 2.7182817 (e1)

Más funciones matemáticas (3) log: Logaritmo

– (log 5) → 1.609438 (log10 5)– (log 8 2) → 3 (log2 8)

sin y cos: Funciones trigonométricas (en radianes):

– (sin 1) → 0.84147096– (cos 1) → 0.5403023

Más funciones matemáticas (4) 1+ : Incrementa en uno.

– (1+ 5) → 6 1- : Decrementa en uno.

– (1- 5) → 4 gcd: Máximo común divisor.

– (gcd 15 10) → 5

Predicados Son procedimientos que regresan t o nil. atom: ¿es un átomo? numberp: ¿es un número? listp: ¿es una lista? symbolp: ¿es un símbolo? zerop: ¿es el número 0? plusp: ¿es un número positivo? Otros: minusp, evenp, oddp, null.

Definición de funciones defun nos permite definir nuestras propias funciones:

– (defun nombre (arg1 arg2 arg3 ...) cuerpo) Por ejemplo:

– (defun inc5 (n) (+ 5 n))– Define la función llamada inc5 que incrementa en 5

su único argumento llamado n.– (inc5 3) → 8

Parámetros opcionales (1)

En Lisp, las funciones pueden definirse con parámetros opcionales.

Por ejemplo, sea la función raiz que regresa la raíz cuadrada si es invocada con un solo parámetro y la raíz n si es invocada con 2 parámetros.

Parámetros opcionales (2)((defun raiz (x &optional n)

(if n (expt x (/ n))

(sqrt x)) )

Si al invocar raiz lo hacemos con un sólo parámetro, este se asigna a x y n se vuelve nil.

(raiz 25) → 5 {X=5, n=nil}

Si lo hacemos con dos parámetros, x toma el primer valor y n toma el segundo

(raiz 64 4) → 4 {x=64, n=4}

Parámetros opcionales (3) También podemos definir el valor por omisión para el

parámetro opcional:

En este caso, si raiz es llamado con un solo parámetro, n toma el valor de 2.

• (raiz 25) → 5 {X=5, n=2}

(defun raiz (x &optional (n 2))

(expt x (/ n)) )

Entrada y salida Las funciones de Entrada/Salida más comunes son: Entrada:

– read Salidas básicas:

– print - prin1– princ - terpri

Salida con formato:– format

Ejemplo de read• read causa que el programa se detenga en espera

de una entrada desde el teclado:

Cuando el intérprete encuentra el read, espera por una entrada desde el teclado y la entrega a la función +.

(+ 10 (read))

print• print toma una cadena o un átomo como

argumento, la despliega y regresa el argumento.• print antecede su argumento con un retorno de

carro y un avance de línea y la sigue con un espacio• (print “Hola Mundo!”)

– “Hola Mundo!” ; valor desplegado– “Hola Mundo!” ; valor que regresa

prin1• prin1 funciona igual que print, pero no agrega ni

el retorno de carro ni el avance de línea al inicio ni el espacio al final.

• (prin1 “hola”)– “hola” ; valor desplegado– “hola” ; valor que regresa

princ y terpri

• princ es igual a prin1 sólo que no imprime las comillas de la cadena de caracteres.

• (princ “Hola Mundo!”)– Hola Mundo! ; valor desplegado– “Hola Mundo!” ; valor que regresa

• terpri no toma argumentos, sólo introduce un retorno de carro y un avance de línea y regresa nil.

Un ejemplo con E/S básicas(defun area-circulo ()

(terpri)

(princ “Por favor, teclea el radio:”)

(setq radio (read))

(princ “El area del circulo es: ”)

(princ (* pi radio radio))

(terpri)

)

format (1) La función format nos permite generar salidas mejor

formadas que las operaciones de salida básica. Su sintáxis es:

– (format <destino> <cadena> arg1 arg2... argn)

Para nuestros propósitos <destino> será t, que es la salida por omisión, la pantalla de video.

format (2) En la <cadena> se introduce la cadena de

caracteres de salida que se desee desplegar junto con algunas directivas de formato que especifican como deben representarse los argumentos arg1 ... argn.

Las directivas de formato deben aparecer en el mismo orden que los argumentos a desplegar.

Directivas de formato (3) Las directivas de formato son precedidas por la tilde (~)

para identificarlas como tales. Algunas directivas de formato son:

– ~A: El argumento se despliega como con princ– ~S: El argumento se despliega como con prin1– ~D: El argumento debe ser entero y se despliega en

decimal.– ~F: El argumento debe ser un número y se despliega en

decimal con punto flotante.– ~%: Se despliega una nueva línea

Ejemplo de format

;;; area-circulo2;;; Ilustra el uso de format(defun area-circulo2 () (terpri) (princ "Por favor, teclea el radio: ") (setq radio (read)) (format t "El area del circulo con radio ~4F es: ~7F~%” radio (* pi radio radio)))

Capturando la sesión Lisp nos provee un medio para capturar los resultados de

una sesión interactiva:– (dribble “archivo_salida.txt”)

Esto indica a Lisp que envie una copia de todo lo que aparece en pantalla al archivo “archivo_salida.txt”

Para detener la captura:– (dribble)

Que indica a Lisp que detenga la captura.

Editando programas Para editar un programa de Common Lisp se puede

utilizar cualquier editor de texto que maneje texto plano.

En Windows, podemos usar notepad En Linux, podemos usar vi o emacs. Por convención, los archivos con código de Common

Lisp usan la extensión .lsp En Windows, desde una ventana de DOS, tecleamos notepad nombrearch.lsp

Cargando archivos Para cargar un archivo con código Lisp, desde el

prompt de Common Lisp tecleamos: (load “nombrearch.lsp”)

En nuestro caso, tecleamos:

(load “z:/nombrearch.lsp”). Esto supone que el archivo está almacenado en la

raíz de la unidad Z de Windows.

Estructuras de control (1) Decisiones condicionales

– (if condición acción-verdadero acción-falso)

Por ejemplo:– (defun mayor (a b) (if (> a b) a b))

– (mayor 5 3) → 5– (mayor 4 6) → 6

Estructuras de control (2)• cond (conditional) es similar a if..then..else. Sintaxis:

Cada prueba se evalúa hasta que una de ellas resulta diferente de nil, en cuyo caso se ejecutan las acciones asociadas y termina el cond.

(cond (prueba1 accion11 accion12 ... accion1n)

(prueba2 accion21 accion22 ... accion2m)

: : : :

(pruebak accionk1 accionk2 ... accionkl))

Ejemplo de cond(defun compara (a b) (cond((= a b) (princ “A igual a B”))

((< a b) (princ “A es menor que B”)) (t (princ “A es mayor que B”)))

)

(compara 4 5) → “A es menor que B”(compara 4 4) → “A es igual a B”(compara 5 4) → “A es mayor que B”

Estructuras de control (3) case es otra forma condicional Sintaxis:

(case clave

(valor1 accion11 accion12 ... accion1n)

(valor2 accion21 accion22 ... accion2m)

: : : :

(clavek accionk1 accionk2 ... accionkl)

(otherwise acciond1 acciond2 ...acciondn))

Ejemplo de case(defun figura (forma r) (case forma (circulo (* pi r r)) (esfera (* 4 pi r r)) (otherwise (princ “figura no conocida”)) ))

> (figura 'circulo 1) → 3.141592...> (figura 'esfera 1) → 12.5336....> (figura 'cuadrado 2) → “figura no conocida”

Funciones recursivas Una función recursiva es aquella que puede usarse a

sí misma. Por ejemplo:• factorial(n) puede definirse recursivamente

como:– 1 para n=0– n*factorial(n-1) para n>1

Factorial(n) en Lisp

;;; Factorial de n como una;;; función recursiva(defun fact (x) (if (= x 0) 1 (* x (fact (1- x))) ) )

Esta es una función recursiva simple porque en su definición se llama a sí misma una sola vez.

Más funciones recursivas simples• Mn se puede definir recursivamente como:

– 1 para n=0– M*Mn-1 para n>0

En Lisp:

(defun potencia (m n)

(if (zerop n) 1

(* m (potencia m (1- n)))

)

)

Longitud de una lista

;;; Obtiene la longitud de la lista

(defun longitud (lista)

(if (endp lista) 0

(1+ (longitud (rest lista)))

)

)

Otro ejemplo de recursión simple:

Funciones recursivas dobles La función de Fibonacci(n) se define como:

– 1 para n=0– 1 para n=1– Fibonacci(n-1) + Fibonacci(n-2) para n > 1

Esta función se llama dos veces a sí misma, por lo que se dice que tiene recursión doble.

Fibonacci en Lisp

;;; Obtiene la función de Fibonacci

;;; con recursión doble.

(defun fibonacci (n)

(if (or (zerop n) (= n 1)) 1

(+ (fibonacci (1- n)) (fibonacci (- n 2)) )

)

)

Mapcar y Funcall• Mapcar es una instrucción que se utiliza para transformar

listas. Sintáxis:

– (mapcar #’procedimiento lista) Mapcar genera una nueva lista con los elementos de lista afectados por procedimiento.

Nota: #’ es una abreviatura de function, que define el átomo siguiente como una función.

Ejemplos de mapcar

(mapcar #’1+ ‘(1 2 3)) → (2 3 4)

(mapcar #’oddp ‘(3 4 5)) → (T NIL T)

• Suponiendo que inc5 está definida como:

(defun inc5 (n) (+ n 5))

Entonces:

(mapcar #’inc5 ‘(3 4 5)) → (8 9 10)

Funcall

• Funcall aplica el argumento inicial al valor de los otros argumentos.

Sintáxis:– (funcall #’arg0 arg1 arg2 ... argn)

Esta instrucción produce átomos o listas dependiendo del valor de arg0.

Ejemplos de funcall

(funcall #’1+ 1 2 3) → 6

(funcall #’append ‘(a b) ‘(c d))

→ (a b c d)

(funcall #’member ‘c ‘(a b c d))

→ (c d)

(funcall #’position ‘d ‘(a b c d e f))

→ 3

Lazos e iteraciones Existen varias maneras de implementar lazos (loops)

e iteraciones en Common Lisp. Algunas de ellas son:

– dolist– dotimes– do– loop

Dolist• Dolist asigna a una variable los valores de los

elementos de una lista en orden hasta que encuentra el fin de la lista.

Sintáxis:– (dolist (var lista) cuerpo)

Ejemplo:

(dolist (x ‘(5 6 7 8))

(print (* x x))

)

Nota: Dolist siempre retorna nil

Dotimes• Dotimes ejecuta las sentencias de su cuerpo n veces

utilizando una variable como contador. Sintáxis:

– (dotimes (var_conta limite) cuerpo) Ejemplo:

(dotimes (i 10)

(print i)

)Note que este ejemplo despliega 0,1,2, ..., 9 dado que el valor inicial de la variable es cero y se incrementa en uno cada iteración. Dotimes siempre retorna nil.

Do (1) Esta es la forma de iteración más complicada ya que

consta de 3 partes:– En la primera se definen las variables a utilizar, sus

valores iniciales y como deben actualizarse en cada iteración.

– En la segunda se especifican la condición de terminación y el valor a regresar.

– La última parte es el cuerpo. Mientras la condición de terminación es falsa, do itera su

cuerpo y actualiza sus variables.

Do (2)

Sintáxis:– (do ( (var1 val_ini_1 actualiza_1) (var2 val_ini_2 actualiza_2)... (varn val_ini_n actualiza_n) ) (cond_termina valor_a_retornar)

cuerpo ) Ejemplo:

(do ((x 0 (1+ x))) ((> x 9) x) (print x)

)

Loop• Loop realiza iteraciones sobre su cuerpo mientras no

encuentre una instrucción (return). Sintáxis:

– (loop cuerpo) Ejemplo:

(setq a 0)

(loop (setq a (1+ a))

(print a)

(when (> a 9) (return a)) )

Funciones lambda Lambda se utiliza cuando se desea crear una función

temporal que no tendrá un nombre. Patrick H. Winston sugirió sustituir, en nuestra

imaginación, la frase “defun-anónimo” por “lambda”. Sintáxis:

– (lambda (arg1 arg2 ... argn) cuerpo )

Ejemplo de lambda El siguiente ejemplo muestra el uso de lambda:

Se define una función anónima que incrementa en 2 y se aplica a una lista por medio de mapcar.

(mapcar #’(lambda (x) (+ x 2))

‘(1 3 5 7)

)