introducción al lenguage common lisp

Anuncio
INTRODUCCIÓN AL
LENGUAGE COMMON
LISP
IIIA 2005-2006
Introduction
IIIA
TAPIA 2005-2006
2
Introducción
IIIA
Bibliografia básica:
- Peter Norvig: Artificial Intelligence
Programming: Case Studies in Common Lisp
- Steele Jr., Guy L : CommonLISP the
language second edition. Digital Press
TAPIA Site (Paul Graham)
Implementaciones de CommonLisp:
MCL
Harlequin
Allegro
LispWorks (+ CAPI)
www.lispworks.com
www.franz.com
www.digitool.com
CLOS (Object System)
CLIM (Interface Manager)
3
TAPIA 2005-2006
Introducción: LIST Processing
IIIA
Cuando se inicia la ejecución de LISP siempre aparece un prompt como >
Después se puede teclear y obtener resultados
> (+ 2 2)
4
Las expresiones aritméticas siguen la notación prefija. Los resultados
de los cálculos son impresos por el evaluador. La notación préfija es más
compacta que la infija
> (+ 1 2 3 4 5 6 7 8 9 10) Æ 55
> (- (+ 9000 900 90 9) (+ 5000 500 50 5)) Æ 4444
Las expresiones se pueden anidar. La regla de evaluación es mucho más
simple que la usual en matemáticas u otros lenguajes de programación.
Primero se evaluan los argumentos y posteriormente se aplica la función
sobre los resultados de la evaluación.
Una diferencia inicial para programadores de otros lenguajes de
programación es que no hay diferencia entre expresión y sentencia. en C
2 + 2 tiene un valor, en cambio x = 2 + 2 no. En LISP toda expresión,
tenga efecto o no, devuelve un valor.
TAPIA 2005-2006
4
Symbolic Computation
IIIA
Las reglas léxicas son mucho más simples en LISP. Solo hay paréntesis,
comillas (sencilla, doble y backquote) espacios y comas. El punto y coma
no separa expresiones (no es necesario debido a los paréntesis) sino que
inicia comentarios.
LISP permite la manipulación de símbolos, y la construcción de
estructuras de datos complejos a partir de ellos.
> (append '(Carlos Antonio) '(Carmen Rosa))
(CARLOS ANTONIO CARMEN ROSA)
La parte extraña es el ('), que sirve para bloquear la evaluación de una
expresión y devolverla literalmente.
> '(Carlos Antonio) Æ (CARLOS ANTONIO)
> 'A Æ A
> (quote A) Æ A
> '2 Æ 2
>2Æ2
5
TAPIA 2005-2006
Symbolic Computation
IIIA
> '(+ 2 2) Æ (+ 2 2)
> (+ 2 2) Æ 4
> A Æ Error: A is not a bound variable
> (Carlos 'Antonio) Æ Error: Carlos is not a function
Los cálculos simbólicos y numéricos se pueden mezclar.
> (+ 2 (length '(a b c d))) Æ 6
LISP no otorga ninguna semántica a los símbolos que manipula.
CommonLISP contiene un conjunto de funciones predefinidas que es
necesario conocer. Como +, append, length.
Los símbolos en CommonLISP no son casesensitive.
Muchos signos de puntuación son autorizados para formar parte de los
símbolos: '?!$/<=>'
TAPIA 2005-2006
6
Variables
IIIA
Los símbolos se utilizan para dar nombre a las variables. Una variable
puede tomar como valor cualquier objeto LISP.
> (setf p '(esto es una asignacion))
> p Æ (esto es una asignacion)
> (setf x 10)
> (+ x x) Æ 20
> (+ x (length p)) Æ 14
> (setf a 3 b 5)
Los símbolos se utilizan también para dar nombre a las funciones. Un
mismo símbolo puede ser a la vez nombre de una variable y nombre de
una función.
7
TAPIA 2005-2006
Special forms
IIIA
En los ejemplos anteriores setf viola la regla de evaluación. No evalua sus
argumentos y luego aplica la función al resultado de esta evaluación. Setf
no es una función. Se trata de uno de los componentes de la sintaxis
básica de LISP. A las expresiones sintácticas de LISP se las conoce
como Special forms. Por ejemplo,
(setf x (+ 1 2) )
A veces se denomina Special form a los símbolos como setf y a veces a
las expresiones encabezadas por estos símbolos, lo cual puede crear una
cierta confusión.
A lo largo de esta introducción veremos unos cuantas special forms de
CommonLisp.
TAPIA 2005-2006
8
Listas
IIIA
Dado que las listas son esenciales en LISP, veremos unas cuantas funciones de
procesado de listas.
> p Æ (esto es una asignacion)
> (first p) Æ esto ; equivalente a (car p)
> (second p) Æ es ; equivalente a (cadr p)
> (third p) Æ una ; equivalente a (caddr p), etc.
> (fifth p) Æ nil
> (length p) Æ 4
Algunos detalles sobre listas. rest (o cdr) devuelve la lista resultante de
eliminar el primer elemento de la lista argumento. NIL y () son completamente
equivalentes. NIL también se utiliza para representar el valor falso.
Las listas pueden contener sublistas como elementos.
> (setf x '((una sublista) 2 (tercero) ((4)) 5)) Æ ((una sublista) 2 (tercero) ((4)) 5))
> (first x) Æ (una sublista)
> (second x) Æ 2
> (third x) Æ (tercero)
> (fourth x) Æ ((4))
> (second (first x)) Æ sublista
9
TAPIA 2005-2006
Listas
IIIA
Aparte de acceder a los elementos de las listas, también podemos
construir listas.
> p Æ (esto es una asignación)
> (cons 'porque p) Æ (porque esto es una asignación)
> (cons (first p) (rest p)) Æ (esto es una asignación)
> (setf ciudad (list 'Paris 'Roma)) Æ (paris roma)
> (list p 'de (list ciudad) 'tachin) Æ ((esto es una asignacion) de ((paris
roma)) tachin)
> (cons 'Paris (cons 'Roma ())) Æ (paris roma)
> (append p ciudad) Æ (esto es una asignacion paris roma)
Cons viene de Construct. Estas funciones crean nuevas listas sin
destruir las listas preexistentes.
> (last p) Æ (asignacion)
> (first (last p)) Æ asignacion
TAPIA 2005-2006
10
Bases listas
IIIA
o Para las listas solo es necesario
o Lectura
o first
o Rest
o Escritura
o cons
o nil
11
TAPIA 2005-2006
Funciones
IIIA
La forma especial defun viene de "define function". Se utiliza para definir
funciones.
(defun last-name (name)
"Selecciona el apellido de un nombre representado como una lista. (en
formato sajón)"
(first (last name)))
La función recibe un nombre last-name, tiene una lista de parámetros que
contiene un único parámetro (name). También tiene una cadena de documentación
que dice que es lo que la función hace. El cuerpo de la función es (first (last
name)). En general
(defun function-name (parameter ...)
"Documentation string"
function-body ...)
Una vez definida, la función se puede utilizar como cualquier otra función LISP.
> (last-name '(John Q Smith)) Æ SMITH
> (last-name '(Antonio De las Cruces Revueltas)) Æ REVUELTAS
> (last-name '(Aristoteles)) Æ Aristoteles
TAPIA 2005-2006
12
Funciones
IIIA
Podemos definir la función first-name
(defun first-name (name)
"Selecciona el nombre de pila de name representado como lista"
(first name))
Las razones de hacerlo son: legibilidad y mantenimiento.
> (setf nombres '((Sir Antonio Lopez) (Señor Pepe Galvez)
(Don Pepe Cuena) (Mr Carlos Sierra)))
((Antonio Lopez) (Pepe Galvez) (Pepe Cuena) (Carlos Sierra))
> (mapcar #'last-name nombres)
(LOPEZ GALVEZ CUENA SIERRA)
13
TAPIA 2005-2006
Utilizando funciones
IIIA
La notación #' relaciona el nombre de la función con la función misma. En
este sentido es similar con la notación 'x. La llamada a mapcar anterior
es equivalente a
(list (last-name (first nombres))
(last-name (second nombres))
...)
Mapcar viene de "to map" una función sobre los sucesivos car delos
argumentos. Car viene de "contents of the address register" y cdr de
"contents of the decrement register" las instrucciones utilizadas en la
primera implementación de LISP sobre el IBM 704.
> (mapcar #'- '(1 2 3 4)) Æ (-1 -2 -3 -4)
> (mapcar #'+ '(1 2 3 4) '(10 20 30 40)) Æ (11 22 33 44)
Podemos eliminar los títulos honoríficos de los nombres
(defparameter *titulos*
'(Mr Mrs Don Señor Dr Sir)
"Lista de títulos que pueden aparecer al inicio de un nombre")
TAPIA 2005-2006
14
Más
IIIA
Defparameter es otra forma especial que define un parámetro, es decir,
una variable que no cambia a lo largo de la computación.
Así ahora podemos cambiar la implementación.
(defun first-name (name)
"Bla bla bla"
(if (member (first name) *titulos*)
(first-name (rest name))
(first name)))
> (first-name '(Mr Dr Don Pepe Cuena)) Æ Pepe
Haciendo una traza podemos ver que ocurre
> (trace first-name)
(FIRST-NAME)
15
TAPIA 2005-2006
Trace
IIIA
> (first-name '(Mr Dr Don Pepe Cuena))
(1 ENTER FIRST-NAME: (MR DR DON PEPE CUENA))
(2 ENTER FIRST-NAME: (DR DON PEPE CUENA))
(3 ENTER FIRST-NAME: (DON PEPE CUENA))
(4 ENTER FIRST-NAME: (PEPE CUENA))
(4 EXIT FIRST-NAME: PEPE)
(3 EXIT FIRST-NAME: PEPE)
(2 EXIT FIRST-NAME: PEPE)
(1 EXIT FIRST-NAME: PEPE)
PEPE
TAPIA 2005-2006
16
Funciones High-order
IIIA
Las funciones en LISP se pueden crear y llamar, como ya hemos visto,
pero tambien se pueden manipular como cualquier otro tipo de objeto. Ya
hemos visto un ejemplo de programación high-order: mapcar.
(defun mappend (fn lista)
"Aplica fn a todos los elementos de lista y hace un append de los
resultados"
(apply #'append (mapcar fn lista)))
veamos como funciona el apply
> (apply #'+ '(1 2 3 4)) Æ 10
> (apply #'append '((1 2 3) (a b c))) Æ (1 2 3 a b c)
Definimos una función auxiliar
> (defun self-and-double (x) (list x (+ x x)))
> (self-and-double 3) Æ (3 6)
> (apply #'self-and-double '(3)) Æ (3 6)
> (mapcar #'self-and-double '(1 10 20)) Æ ((1 2) (10 20) (20 40))
> (mappend #'self-and-double '(1 10 20)) Æ (1 2 10 20 20 40)
17
TAPIA 2005-2006
Funcall and Lambda
IIIA
funcall es similar a apply con la diferencia sus argumentos no estan en una lista.
> (funcall #'+ 2 3) Æ 5
> (apply #"+ '(2 3)) Æ 5
> (funcall #'+ '(2 3)) Æ Error (2 3) is not a number
Es posible definir funciones sin darles nombre. Esto se hace con la sintaxis
especial Lambda.
Russell
x(x + x)
Church
^x(x + x) Æ Λx(x + x) Æ λx(x + x) 1941
McCarthy
(lambda (x) (+ x x))
1958
En general (lambda (parameters ...) body ...)
una expresión lambda es un nombre noatómico para una función. Así su uso es
exacto al de una función como append.
primer argumento de una llamada
> ((lambda (x) (+ x 2)) 4) Æ 6
obtención de la función real
> (funcall #'(lambda (x) (+ x 2)) 4) Æ 6
TAPIA 2005-2006
18
Más
IIIA
La forma de evaluación es un poco más complicado de lo explicado hasta ahora.
Si el primer elemento de una lista es una forma especial, la expresión se evalua
bajo las reglas de esa forma especial. Sinó, el primer argumento es evaluado
como una función, pudiendo ser un símbolo o una función lambda, el resto de
elementos se evaluan como se ha explicado hasta ahora.
Cuando una función aparece en una posición diferente de la primera debemos
utilizar #' sinó las expresiones serán evaluadas de forma normal y no serán
tratadas como funciones.
> append Æ Error: APPEND is not a bound variable
> (lambda (x) (+ x 2)) Æ Error: Lambda is not a function
Hay dos razones que justifican la existencia de funciones lambda (sin nombre)
• Provoca confusión crear nombres innecesarios de funciones en un programa.
• Nos permite crear funciones en tiempo de ejecución! Esta herramienta de
programación es muy potente y no es posible usarla en la mayoria de lenguajes.
Estas funciones de tiempo de ejecución se denominan clausuras o cierres.
19
TAPIA 2005-2006
Que hace a LISP diferente
IIIA
• Soporte de listas
• Manejo automático del almacenamiento
• Tipaje dinámico
• Funciones como objetos de primera clase
• Sintaxis uniforme
• Entorno interactivo
• Extensibilidad
• Historia
TAPIA 2005-2006
20
LISP style
IIIA
• Ser específico
Ejemplo: When y if
• Usar abstracciones
Ejemplo: last-name y caddar
• Ser conciso
Ejemplo: find y loop
• Usar las herramientas proporcionadas
Ejemplo: find
• No ser oscuro
Ejemplo: otra vez find
• Ser consistente
Ejemplo: usar siempre la misma primitiva para lo mismo
A veces hay conflictos
(setq x val) es más específico que (setf x val) pero setf es más
consistente ya que sirve para más ocasiones.
21
TAPIA 2005-2006
Special forms para definiciones
IIIA
• Funciones
(defun function-name (parameter ...) "opt. doc." body...)
• Macros
(defmacro macro-name (parameter ...) "opt. doc." body ...)
• Variables
(defvar variable-name initial-value "opt. doc.")
La expresión initial-value es evaluada sólo si la variable no tiene valor
cuando se le requiere. Es opcional.
• Parámetros
(defparameter variable-name value "opt. doc.")
• Constantes
(defconstant variable-name value "opt. doc.")
• Estructuras
(defstruct structure-name "opt. doc." slot...)
Todas las formas def- definen símbolos globales. Para definir variables
y funciones locales es necesario utilizar let y labels.
TAPIA 2005-2006
22
Estructuras
IIIA
Veamos las estructuras
(defstruct name first (middle nil) last)
Se definen automáticamente la función constructora make-name, el
predicado name-p, y las funciones accesoras name-first, name-middle y
name-last
> (setf b (make-name :first 'pepe :last 'cuena))
#S(NAME :FIRST PEPE :LAST CUENA)
> (name-first b) Æ pepe
> (name-middle b) Æ nil
> (name-last b) Æ cuena
> (name-p b) Æ T
> (name-p 'pepe) Æ NIL
> (setf (name-middle b) 'Nolose) Æ nolose
>b
#S(NAME :FIRST PEPE :MIDDLE NOLOSE :LAST CUENA)
23
TAPIA 2005-2006
Special forms para condicionales
IIIA
Hemos visto el if. Ahora veremos el cond y como las demas pueden expresarse
como estas
(cond (test result...)
(test result...)
...)
Evaluación secuencial de los tests, cuando uno evalua diferente de nil se evalua
el (los) resultados a continuación. Si ninguno evalua no-nil el resultado es nil. Se
devuelve el resultado de la última expresión evaluada.
(when test a b c)
(if test (progn a b c))
(cond (test a b c))
(unless test x y)
(if (not test) (progn x y))
(cond ((not test) x y))
(and a b c)
(if a (if b c))
(cond (a (cond (b c))))
TAPIA 2005-2006
(or a b c)
(if a a (if b b c))
(cond (a) (b) (c))
(case a (b c) (t x))
(if (eql a 'b) c x)
(cond ((eql a 'b) c) (t x))
24
IIIA
Special forms para manejar variables y
posiciones
La forma especial setf es la utilizada para assignar valores a una variable o a una
posición (variable generalizada).
LISP
PASCAL
(setf x 0)
x := 0;
(setf (aref A i j) 0)
A[i,j] := 0;
(setf (rest list) nil)
list^.rest := nil;
(setf (name-middle b) 'Q)
b^.middle := "Q";
Las expresiones que se pueden encontrar a la izquierda de una sentencia de
asignación en Pascal están limitadas por la sintaxis de Pascal, en LISP es posible
definir nuevas expresiones a través de las forma especial defsetf.
Hay otras formas especiales más espécificas. Por ejemplo (rplacd list nil) tiene el
mismo efecto que (setf (rest list) nil)
Para asignar variables es muy común el uso de setq.
En cualquier caso la programación funcional pura no permite la asignación, y no es
extraño ver programas en los que esta no aparece. La forma habitual es el uso
de la vinculación en lugar de la asignación. Es decir usar parámetros de funciones
o variables locales dentro de un let.
(let ((x 40)
((lambda (x y)
(y (+ 1 1)))
(+ x y))
(+ x y))
40 (+ 1 1))
TAPIA 2005-2006
IIIA
25
Funciones y formas especiales para
repetición
dolist
iter. sobre los elem. de una lista
dotimes
iter. sobre enteros sucesivos
do, do*
iter. general. Sintaxis sucinta
loop
iter. general. Sintaxis prolija
mapc, mapcar
iter. sobre elem. de una lista
some, every
iter. sobre lista hasta condición (notevery, notany)
(every #'characterp "abc")
find, reduce, ...
funciones más específicas
recursión
repetición general.
Para ver las diferencias haremos versiones de la función length.
(dolist (variable list optional-result) body...)
(defun length1 (lista)
(let ((len 0))
(dolist (element list)
(setf len (+ len 1)))
len))
TAPIA 2005-2006
26
IIIA
mapc tiene dos argumentos, uno una función y el otro una lista. Aplica la
función a cada elemento de la lista.
(defun length2 (lista)
(let ((len 0))
(mapc #'(lambda (element)
(incf len))
lista)
len))
27
TAPIA 2005-2006
IIIA
Funciones y formas especiales para
repetición II
(dotimes (variable number optional-result) body...)
Dotimes no es apropiado para length, por supuesto.
(do ((variable initial next) ...)
(exit-test result)
body...)
(defun length3 (list)
(do ((len 0 (+ len 1))
(l list (rest list)))
((null l) len)))
TAPIA 2005-2006
28
IIIA
La sintaxis de loop representa un lenguaje en sí misma. No es muy
utilizada debido a su caracter no funcional. Aqui vemos dos ejemplos.
(defun length4 (list)
(loop for element in list
count t))
(defun length5 (list)
(loop with len = 0
until (null list)
for element = (pop list)
do (incf len)
finally (return len)))
29
TAPIA 2005-2006
IIIA
Funciones y formas especiales para
repetición III
Muchas formas de iteración corresponden a esquemas de programación,
como hemos visto con los casos de dolist o dotimes. LISP proporciona
flexibilidad para construir los esquemas más adecuados. La flexibilidad
viene dada por tres elementos.
1) Aplicación a un número arbitrario de listas.
> (mapcar #'- '(1 2 3) Æ (-1 -2 -3)
> (mapcar #'+ '(1 2) '(10 20) Æ (11 22)
> (mapcar #'+ '(1 2) '(10 20) '(100 200)) Æ (111 222)
2) Palabras clave que varian las comprobaciones
> (remove 1 '(1 2 3 2 1 0 -1)) Æ (2 3 2 0 -1)
> (remove 1 '(1 2 3 2 1 0 -1) :key #'abs) Æ (2 3 2 0)
> (remove 1 '(1 2 3 2 1 0 -1) :test #'<) Æ (1 1 0 -1)
> (remove 1 '(1 2 3 2 1 0 -1) :start 4) Æ (1 2 3 2 0 -1)
3) Predicados en lugar de elementos
> (remove-if #'oddp '(1 2 3 2 1 0 -1)) Æ (2 2 0)
> (remove-if-not #'oddp '(1 2 3 2 1 0 -1)) Æ (1 3 1 -1)
> (find-if #'evenp '(1 2 3 2 1 0 -1)) Æ 2
TAPIA 2005-2006
30
Funciones y formas especiales para
repetición III
IIIA
En las próximas tablas usaremos los siguientes valores
(setf x '(a b c))
(setf y '(1 2 3))
Las funciones de la primera tabla no aceptan palabras clave.
(every #'oddp y) Æ nil
compr. que cada elem satisf. el pred
(some #'oddp y) Æ t
compr. si algún elem satisf. el pred.
(mapcar #'- y) Æ (-1 -2 -3)
aplica la fn a cada elem. y dev. Lista
(mapc #'print y) imprime 1 2 3 aplica la fn a cada elem.
Las siguientes funciones sí que permiten las palabras clave.
(member 2 y) Æ (2 3)
ver si el elem. esta en la lista
(count 'b x) Æ 1
contar el núm. de apariciones
(delete 1 y) Æ (2 3)
eliminar elementos
(find 2 y) Æ 2
encontrar elementos
(position 'a x) Æ 0
posición de un elemento
(remove 2 y) Æ (1 3)
como delete pero con copia
(substitute 4 2 y) Æ (1 4 3)
reemplazar elementos
31
TAPIA 2005-2006
Repetición via recursión
IIIA
Una de las características que históricamente caracterizó a LISP fue la
posibilidad de permitir recursión. La recursión es un mecanismo general de
realizar repetición.
(defun length9 (lista)
(if (null lista) 0 (+ 1 (length9 (rest list)))))
Las versiones recursivas sobre listas son fáciles de ver debido a la definición
recursiva de las mismas. Una lista es o bien vacia o bien un elemento
concatenado a una lista.
Los árboles son difíciles de manejar si no es a través de recursión.
La ineficiencia es una objeción clásica a la recursión. Vease
(defun length10 (list) (length10-aux list 0))
(defun length10-aux (sublist len-so-far)
(if (null sublist)
len-so-far
(length10-aux (rest sublist) (+ 1 len-so-far))))
TAPIA 2005-2006
32
IIIA
La segunda versión es recursiva por la cola. Los compiladores pueden
mejorar la eficiencia de estas funciones.
Las dos versiones pueden combinarse de forma elegante en CommonLisp
(defun length11 (lista &optional (len-so-far 0))
(if (null lista) len-so-far
(length11 (rest lista) (+ 1 len-so-far))))
33
TAPIA 2005-2006
Repetición via recursión
IIIA
Otra posibilidad de aumentar la elegancia es introducir funciones
locales!
(defun length12 (lista)
(labels
((length13 (la-lista len-so-far)
(if (null la-lista)
len-so-far
(length13 (rest la-lista) (+ 1 len-so-far))))
(length13 lista 0)))
La forma especial labels es la forma de definir funciones locales
(labels
((function-name (parameter...) function-body...) ...)
body-of-labels)
TAPIA 2005-2006
34
Otras formas especiales
IIIA
Hay otras formas especiales que no encajan en los tipos anteriores hemos visto
ya
'x ≡ (quote x) y #'f ≡ (function f)
> (progn (setf x 0) (setf x (+ x 1)) x) Æ 1
> (trace length9) Æ (length9)
> (length9 '(a b c))
(1 ENTER LENGTH: (A B C))
(2 ENTER LENGTH9: (B C))
(3 ENTER LENGTH9: (C))
(4 ENTER LENGTH9: NIL)
(4 EXIT LENGHT9: 0)
(3 EXIT LENGTH9: 1)
(2 EXIT LENGTH9: 2)
(1 EXIT LENGTH9: 3)
3
>
35
TAPIA 2005-2006
IIIA
> (untrace length9) Æ (length9)
> (length9 '(a b c)) Æ 3
Finalmente la forma especial return sirve para salir de un bloque de código. Los bloques se
construyen con la forma especial block or por las formas de iteración do, do*, dolist, dotimes
o loop.
(defun product (numbers)
(let ((prod 1))
(dolist (n numbers prod)
(if (= n 0) (RETURN 0) (setf prod (* n prod))))))
TAPIA 2005-2006
36
Macros
IIIA
Muchas de las formas especiales que hemos comentado no son tales formas. Son
macros que el compilador expande en tiempo de compilación. LISP proporciona un
conjunto de macros predefinidas y permite al usuario definir nuevas macros. Las
macros se definen con la foma especial defmacro. Para construir una macro hay
que plantearse varias cosas:
• Es necesaria la macro?
• Escribir la sintaxis de la macro.
• Imaginar en que debe expandirse la macro.
• Escribir el código de la macro usando defmacro.
Para la macro while una sintaxis puede ser
(while test body...)
la expansión será (loop (unless test (return nil)) body...)
la definición es
(defmacro while (test &rest body)
(list* 'loop
(list 'unless test '(return nil))
body))
37
TAPIA 2005-2006
Macros
IIIA
La expansión se puede ver con la ayuda de la función macroexpand-1.
> (macroexpand-1 '(while (< i 10)
(print (* i i))
(setf i (+ i 1))))
(LOOP (UNLESS (< I 10) (RETURN NIL))
(PRINT (* I I)) (SETF I (+ I 1)))
> (setf i 7) Æ 7
> (while (< i 10)
(print (* i i))
(setf (+ i 1)))
49
64
81
nil
TAPIA 2005-2006
38
Notación backquote
IIIA
La parte más complicada de las macros es definir el código para la expansión.
Hay una notación en CommonLisp que ayuda a este propósito.
la backquote "`" significa que en la expresión a continuación nada se evaluará a
no ser que vaya precedido de "," o de ",@", la diferencia está en que la expresión
precedida de ",@" debe evaluar a una lista, y el efecto es que el nivel superior
de paréntesis desaparecerá.
(defmacro while (test &rest body)
`(loop (unless ,test (return nil)) ,@body))
Al final de una lista ",@" tiene el mismo efecto que "." seguido de ",".
> (setf test1 '(a test)) Æ (a test)
> `(this is ,test1) Æ (this is (a test))
> `(this is ,@test1) Æ (this is a test)
> `(this is . ,test1) Æ (this is a test)
> `(this is ,@test1 -- this is only ,@test1) Æ (this is a test -- this is only a test)
39
TAPIA 2005-2006
Funciones sobre listas
IIIA
En la siguiente tabla usaremos
(setf x '(a b c))
(setf y '(1 2 3))
(first x) Æ a
(second x) Æ b
(third x) Æ c
(nth 0 x) Æ a
(rest x) Æ (b c)
(car x) ≡ (first x)
(cdr x) ≡ (rest x)
(last x) Æ (c)
(length x) Æ 3
(reverse x) Æ (c b a)
TAPIA 2005-2006
primer elem. de lista
segundo elem. de lista
tercer elem. de lista
n-ésimo elem. de lista
todos los elem. de lista menos primero
última célula cons de una lista
número de elems. de una lista
lista invertida
40
Listas
IIIA
(cons 0 y) Æ (0 1 2 3)
(append x y) Æ (a b c 1 2 3)
(list x y) Æ ((a b c) (1 2 3))
(list* 1 2 x) Æ (1 2 a b c)
(null nil) Æ t
(null x) Æ nil
(listp x) Æ t
(listp 3) Æ nil
(consp x) Æ t
(consp nil) Æ nil
(equal x x) Æ t
operación de const. de listas
unir juntos los elems.
hacer una nueva lista
append del últ. arg. a los otros
el pred. es cierto en listas vacias
y falso en otro caso
pred. cierto para una lista
y falso en otro caso
pred. es cierto en no-nil listas
y falso para átomos incluido nil
cierto para listas iguales
41
TAPIA 2005-2006
IIIA
(equal x y) Æ nil
(sort y #'>) Æ (3 2 1)
(subseq x 1 2) Æ (b)
y falso para listas diferentes
ordena una lista según un criterio
subsecuencia desde inicio a fin
En el caso de que en (cons a b), b no sea una lista no se trata de un
error. El resultado es (a . b). Esta notación es conocida como par
puntual. (first (cons a b)) Æ a, (rest (cons a b)) Æ b.
La representación de las listas se basa en las celulas cons.
(uno dos tres)
uno
TAPIA 2005-2006
Dos
Tres
42
Igualdad y representación interna
IIIA
Hay cinco predicados de igualdad en LISP. = se utiliza sólo para
números.
Cuando LISP lee un símbolo en dos lugares diferentes garantiza que
sean el mismo símbolo. Ahora bien cuando una lista se lee en dos sitios
no se garantiza que sea exactamente la misma.
(setf x '(uno dos))
uno
Dos
(setf y '(uno dos))
x
(cons 'cero x)
cero
uno
TAPIA 2005-2006
Dos
43
y
Igualdad y representación interna II
IIIA
'x
'0
'(X)
'"XY"
'"xY"
'0
'0
y
eq
eql
equal
equalp
'x
'0
'(X)
'"XY"
'"Xy"
'0.0
'1
T
?
NIL
NIL
NIL
NIL
NIL
T
T
NIL
NIL
NIL
NIL
NIL
T
T
T
T
NIL
NIL
NIL
T
T
T
T
T
T
NIL
TAPIA 2005-2006
44
Funciones sobre secuencias
IIIA
Los LISP originales únicamente disponían de símbolos y listas como
estructuras de datos. LISPs más modernos como CommonLisp proveen
de otras estructuras. Entre ellas se encuentran las secuencias. Las
listas son un caso particular de secuencia. Las funciones de manipulación
de las mismas dependen del tipo de secuencia. Hay algunas funciones
como mapcar que sólo trabajan sobre listas. Otras como concatenate son
genéricas.
(nth n list)
(elt sequence n)
(aref array n)
(char string n)
(bit bitvector n)
(sbit simplebitvector n)
(svref simplevector n)
45
TAPIA 2005-2006
Funciones sobre tablas
IIIA
Las listas de asociación son listas utilizadas para implantar tablas. Una
lista de asociación es una lista de pares puntuales donde cada par es del
tipo (clave . valor). Dada una clave se puede obtener el valor de la tabla.
> (setf state-table '((AL . Alabama) (AK . Alaska) (AZ . Arizona)))
> (assoc 'ak state-table) Æ (AK . Alaska)
> (cdr (assoc 'ak state-table)) Æ Alaska
> (assoc 'tx state-table) Æ nil
También se puede acceder por valor
> (rassoc 'arizona state-table) Æ (AZ . Arizona)
> (car (rassoc 'arizona state-table)) Æ AZ
Las tablas hechas con listas de asociación se manejan de forma simple,
pero son ineficientes. LISP da la posibilidad de definir tablas de hash.
> (setf table (make-hash-table))
> (setf (gethash 'AL table) 'Alabama)
> (setf (gethash 'AK table) 'Alaska)
> (setf (gethash 'AZ table) 'Arizona)
TAPIA 2005-2006
46
Funciones sobre tablas
IIIA
> (gethash 'AK table) Æ Alaska
> (gethash 'TX table) Æ nil
La función remhash borra una pareja clave/valor de una tabla, clrhash las borra
todas y maphash se puede usar para recorrer todas las parejas.
La tercera forma de hacer tablas es mediante las listas de propiedad. Son
parecidas a las a-list.
a-list: ((key1 . val1) (key2 . val2) ...)
p-list: (key1 val1 key2 val2 ...)
La diferencia en su uso es que cada símbolo posee una p-list asociada. Los
valores de las propiedades se obtienen a traves de la función get.
> (setf (get 'state 'AL) 'Alabama)
> (setf (get 'state 'AK) 'Alaska)
> (setf (get 'state 'AZ) 'Arizona)
> (get 'state 'AK) Æ Alaska
> (get 'state 'TX) Æ nil
No hay equivalente de rassoc. Habría que hacerlo colocando otra propiedad
(Abrev por ejemplo).
47
TAPIA 2005-2006
Símbolos
IIIA
o symbol-value
o symbol-function
o symbol-plist
o symbol-name
o symbol-package
o symbolp
o inspect
ocompile
TAPIA 2005-2006
48
Funciones sobre arboles
IIIA
Muchas funciones de LISP tratan expresiones del tipo
( (a) ((b (c) (d e)) a) ) como árboles.
La función copy-tree hace una copia del árbol y tree-equal es similar a equal,
pero permite :test.
> (setf tree '((a b) ((c)) (d e)))
> (tree-equal tree (copy-tree tree)) Æ T
Hay funciones que permiten realizar substituciones de expresiones.
> (subst 'new 'old '(old ((very old)))) Æ (new ((very new)))
> (sublis '((old . new)) '(old ((very old))) Æ (new ((very new)))
> (subst 'new 'old 'old) Æ 'new
(defun english->french (words)
(sublis '((are . va) (book . livre) (friend . ami) (hello . bonjour)
(how . comment) (my . mon) (red . rouge) (you . tu))
worgs))
> (english->french '(hello my friend -- how are you today?))
(bonjour mon ami -- comment va tu today?)
49
TAPIA 2005-2006
Funciones numéricas
IIIA
(+ 4 2) Æ 6
(- 4 2) Æ 2
(* 4 2) Æ 8
(/ 4 2) Æ 2
(> 100 99)
(= 100 100)
(< 99 100)
(random 100)
(expt 4 2)
(sin pi) Æ 0.0
(asin 0) Æ 0.0
TAPIA 2005-2006
suma
resta
multiplicación
división
ÆT
mayor que (también >=)
ÆT
igual que (también /=)
ÆT
menor que (también <=)
Æ 42 números enteros aleatorios
Æ 16 exponenciación (tambien exp, y log)
seno (también cos, tan, ...)
arcoseno (también acos, atan, etc)
50
IIIA
(min 2 3 4) Æ 2
(abs -3) Æ 3
(sqrt 4) Æ 2
(round 4.1) Æ 4
(rem 11 5) Æ 1
mínimo (también max)
valor absoluto
raiz cuadrada
redondeo(tamb. truncate, floor, etc)
resto (también mod)
51
TAPIA 2005-2006
Funciones sobre conjuntos
IIIA
Uno de los usos de LISP es tratar las listas como conjuntos. Para ello
proporciona un conjunto de funciones. Usaremos los siguientes valores
(setf r '(a b c d)) Æ (a b c d)
(setf s '(c d e)) Æ (c d e)
(intersection r s) Æ (c d)
(union r s) Æ (c d)
(set-difference r s) Æ (a b)
(member 'd r) Æ (d)
(subsetp s r) Æ nil
(adjoin 'b s) Æ (b c d e)
(adjoin 'c s) Æ (c d e)
intersección
unión
r-s
ver si el elem. perten. al conj.
ver si es subconjunto
añadir un elemento a un conj.
pero sin duplicar
Otra posibilidad es utilizar secuencias de bits para representar
conjuntos de un universo de elementos reducido. La computación es en
este caso más eficiente.
TAPIA 2005-2006
52
Funciones destructivas
IIIA
Las funciones matemáticas sólo calculan resultados a partir de valores pero no
"hacen" nada. Algunas funciones de LISP pueded "hacer" algo aparte de la propia
computación. En otros lenguajes a estas funciones se las denomina
procedimientos, y pueden causar graves trastornos si no se utilizan con
precaución. A veces, en cambio, son de gran utilidad.
> (setf x '(a b c)) Æ (a b c)
> (setf y '(1 2 3)) Æ (1 2 3)
> (append x y) Æ (a b c 1 2 3)
append es una función pura. no modifica ni x ni y, en cambio.
> (nconc x y) Æ (a b c 1 2 3)
> x Æ (a b c 1 2 3)
> y Æ (1 2 3)
calcula exactamente lo mismo que append pero modifica el primer argumento. Se
llama destructiva, dado que destruye estructuras preexistentes modificandolas
por nuevas. La ventaja es el espacio de almacenamiento ahorrado.
Otras funciones destructivas son: nreverse, nintersection, nunion, nsetdifference y nsubst.
Un caso especial es delete, version destructiva de remove.
53
TAPIA 2005-2006
Ordenación
IIIA
o Ordenación de secuencias
o destructiva
o (sort ‘(3 4 6 1 78 3 7) #’<)
o (sort “gadeedpkmk” #'char-lessp)
o (sort '("Josep" "Ramon" "Laura" "Joan") #'string-lessp)
o (sort ‘((3 2 4) (4 “ji” true) (32 4 5) (9 8 7)) #'> :key #'car)
TAPIA 2005-2006
54
Entrada/salida
IIIA
La entrada en LISP es muy fácil ya que el lenguaje provee al usuario de un
parser completo cuyo nombre es read. Se utiliza para leer y devolver espresiones
LISP. Si la entrada se puede adaptar para que pueda escribirse en formato de
expresiones LISP, los problemas de entrada se han acabado.
Para leer desde el terminal las funciones read, read-char y read-line devuelven
una expresión, un carácter y una cadena respectivamente.
Para leer de un fichero la función with-open-stream es la más comunmente
utilizada. Asocia un stream a un fichero. Las funciones de lectura tienen un
parámetro opcional que es precisamente el nombre de un stream.
Las funciones de salida son print que imprime cualquier objeto en una nueva linea
dejando un blanco después. prin1 es igual pero sin salto de linea ni blanco. Los
formatos generados por estas funciones son leibles por las funciones de
entrada.La función más utilizada es el format (todo un lenguaje de escritura).
> (with-open-file (stream "Mifichero.txt" :direction :output)
(print '(hello there) stream)
(princ 'goodbye)) Æ goodbye ; y crea el fichero mifichero.txt
> (with-open-file (stream "Mifichero.txt" :direction :input)
(list (read stream) (read-char stream) (read stream)
(read stream nil 'eof)))
((hello there) #\g oodbye eof)
55
TAPIA 2005-2006
IIIA
> (let ((numbers '(1 2 3 4 5)))
(format t "~&~{~ r~^ plus ~} is ~ @r"
numbers (apply #'+ numbers)))
one plus two plus three plus four plus five is XV
(loop (print (eval (read))))
TAPIA 2005-2006
56
Herramientas de depuración
IIIA
En la mayoria de lenguajes hay dos estrategias de depuración:
(1) editar el programa y insertar sentencias de impresión
(2) utilizar un programa depurador que altere el estado interno en
tiempo de ejecución.
En LISP hay una tercera que es (3) hacer anotaciones que no son parte del
programa pero que automáticamente alteran la ejecución del mismo.
Este es el caso de trace y untrace que ya hemos visto. Otro caso es step. (step
expression). Evalua la expresión dando información de cada paso de evaluación.
Otras funciones son:
(apropos 'string) Devuelve todos los simbolos que hacen matching con string.
(describe 'make-string) Da información sobre el símbolo.
(documentation 'first 'function) devuelve la cadena de documentación de la función
first.
Si se quiere mirar y tal vez modificar los componentes de una estructura, la
herramienta es inspect.
57
TAPIA 2005-2006
Valores múltiples
IIIA
Hay funciones en lisp que no se comportan como funciones en el sentido que no
devuelven un único valor. Por ejemplo
(round 5.1) Æ 5 .1
Hay dos valores después de la flecha porque round devuelve el entero y el resto.
La mayoria de las veces los valores múltiples son ignorados y sólo se considera el
primero de ellos.
(* 2 (round 5.1)) Æ 10
Si se quieren obtener todos se debe hacer con la forma especial multiple-valuebind.
(defun show-both (x)
(multiple-value-bind (int rem)
(round x)
(format t "~f = ~d + ~f" x int rem)))
> (show-both 5.1)
5.1 = 5 + 0.1
También se pueden construir funciones que devuelvan múltiples valores.
(values 1 2 3) Æ 1 2 3
TAPIA 2005-2006
58
Que hacer para continuar …
IIIA
Hay varios libros interesantes para aprender técnicas de programación en LISP.
Los mejores son los de Abelson Sussman and Susman y el Norvig.
Peter Norvig: Artificial Intelligence Programming: Case Studies in Common Lisp
El manual del Lenguaje es:
Steele Jr., Guy L : CommonLISP the language second edition. Digital Press.
Paul Graham: On Lisp
TAPIA 2005-2006
o
Multiprocessing
o
Compiler
o
Delivery
o
Debugger
o
…
59
Descargar