1 / 20

LISP II

LISP II. Contenido de la sesión Organización de memoria y Operaciones destructivas Funciones anónimas. Variables. Alcances. A-listas. Pattern matching . Organización de la memoria (1). Celdas CONS Formadas por 2 punteros: CAR y CDR

jariah
Download Presentation

LISP II

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. LISP II • Contenido de la sesión • Organización de memoria y Operaciones destructivas • Funciones anónimas. Variables. Alcances. • A-listas. Pattern matching.

  2. Organización de la memoria (1) • Celdas CONS • Formadas por 2 punteros: CAR y CDR • La función CONS crea una celda CONS a partir de memoria libre > (CONS arg1 arg2) arg1: inicializa la celda CAR arg2: inicializa la celda CDR > (CONS ‘x ‘caza) (x . caza) La notación par-punto es la utilizada por LISP para indicar los elementos apuntados por el CAR y el CDR de una celda CONS. Cuando CDR apunta a NIL, LISP simplifica esta notación no mostrando dicho elemento apuntado. • MODIFICACIÓN DE CELDAS CONS • Con SETF • arg1: dirección de puntero en memoria • arg2: la nueva dirección que deseamos que contenga arg1 > (SETF *c* ‘( x . caza)) (x . caza) > (SETF (CAR *c*) ‘y) (y . caza) > (SETF (CDR *c*) ‘pesca) (y . pesca) > *c* (y . pesca)

  3. x y x y car pesca caza cdr caza caza Organización de la memoria (2) Celda CONS: (CONS ‘x ‘caza) *c* (SETF *c* ‘(x . caza)) *c* (SETF (CAR *c*) ‘y) *c* (SETF (CDR *c*) ‘pesca)

  4. Organización de la memoria (3) • Disgregación de celdas CONS • Asignando NIL al CDR de la/s celda/s que deseamos disgregar • Creando nuevas celdas CONS con SETF >(SETF *d* ‘(A B C)) (A B C) >(SETF *d2* (CDR *d*)) (B C) >*d* (A B C) >(SETF (CDR *d*) nil) nil >(SETF *d3* (CDR *d2*)) (C) >(SETF (CDR *d2*) nil) nil • cada vez que el CDR de una celda se apunta a NIL, el resto de celdas CONS que estaban apuntadas por dicha celda quedan ocupando memoria y no se pueden reutilizar. • Tratar de optimizar las asignación de memoria evitando el uso abusivo de variables globales • Recuperar la memoria usada e inservible (garbage collection)

  5. Organización de la memoria (4) • Garbage Collection • Analizamos el siguiente ejemplo: >(SETF *e* ‘(dato1 dato2 dato3)) (dato1 dato2 dato3) >(SETF *e* ‘(dato4 dato5 dato6)) (dato4 dato5 dato6) >*e* (dato4 dato5 dato6) • La memoria utilizada en la primera asignación de SETF (una serie de datos) queda ligada a la lista inicial y no es accesible • Se denomina basura (garbage) a los objetos usados que ocupan memoria y no pueden volver a ser utilizados. En el caso anterior, son basura: (dato1 dato2 dato3)

  6. e Old-e e dogo galgo mastín labrador dogo galgo mastín labrador Operaciones destructivas • Consideremos el siguiente ejemplo >(SETF e ‘(dogo galgo mastín labrador)) (dogo galgo mastín labrador) >(SETF old-e e) (dogo galgo mastín labrador) >(SETF e (NREVERSE old-e)) (labrador mastín galgo dogo) >e (labrador mastín galgo dogo) >old-e (dogo) • NREVERSE destruye la lista old-e, reasignando punteros con el fin de no generar basura. Al concluir, ambas listas comparten la última celda

  7. NREVERSE redefinido (defun our-nreverse (n) (our-nreverse-1 nil n)) (defun our-nreverse-1 (head tail) (let ((residual (cdr tail))) (our-nreverse-2 (setf (cdr tail) head) residual tail))) (defun our-nreverse-2 (drop residual tail) (if (null residual) tail (our-nreverse-1 tail residual)

  8. Funciones anónimas • Orígenes • Deriva de la notación usada por Whitehead y Russell de los Principia Mathematica • Aplicada por vez primera por Alonzo Church en 1941 en su definición del cálculo lambda del que deriva LISP. • ^x(x + x) (evolución de x-circunflejo) • Λx(x + x) (evolución de ^ a Λ) • λx(x + x) (evolución de Λ a λ) • (lambda (x) (+ x x)) (McCarthy 1958) • Utilización • Mediante la notación #’ • (funcall #’(lambda (x) (+ x x)))

  9. Ejemplos de aplicación • Problema: “Dada la lista (1 2 3), obtener sus cuadrados” • Solución 1 > (defun n-square (n) (expt n 2)) > (defun square-iterate (list) (if (null list) nil (cons (n-square (car list)) (square-iterate (cdr list))))) > (square-iterate ‘(1 2 3)) (1 4 9) • Solución 2 > (mapcar #’(lambda (x) (expt x 2)) ‘(1 2 3)) (1 4 9) • Solución 3 > (mapcar #’n-square ‘(1 2 3)) (1 4 9)

  10. Evaluación • Mediante • Eval: en desuso >(eval ‘(+ 1 2 3 4)) 10 • Funcall: se aplica sobre una lista de argumentos simples >(funcall #‘+ 1 2 3 4) 10 • Apply: se aplica sobre una lista de uno o más argumentos el último de los cuales debe ser una lista >(apply #’+ 1 2 ‘(3 4)) 10 >(apply #’+ ‘(1 2 3 4)) 10

  11. z es lexicamente invisible Alcance léxico (lexical scope) • Este término hace referencia al conjunto de reglas necesarias para determinar, sin ambigüedad, la ligadura asociada a las variables utilizadas en un fragmento de código. • En él, un símbolo hace referencia a la variable que posee dicho nombre en el contexto en el que dicho símbolo aparece >(let ((x 10)) (defun foo () x)) >(let ((x 20)) (foo)) 10 • Cada vez que se efectúa una ligadura entre variables se determina un cierre léxico para la misma. Dicha variable es visible dentro del cierre léxico que le corresponda. > (defun main (z) (ejemplo-de-alcance z 3)) > (defun ejemplo-de-alcance (x y) (append (let ((x (car x))) (list x y)) x z))

  12. Alcance dinámico (dynamic scope) > (let ((x 10)) (defun foo () (declare (special x)) x)) • Para que una variable posea alcance dinámico debemos declararla como special en todos los contextos en los que aparezca • En este ejemplo la x de la función no hace referencia a la variable léxica definida, lo hará a cualquier variable x que sea declarada como especial en el momento de invocar la función • > (let ((x 20)) (declare (special x)) (foo)) 20 • Por tanto, en el alcance dinámico buscamos la variable en el entorno en que fue definida la función. • Utilidad: para dar a una variable global un valor temporal diferente. > (let ((*print-base* 16)) (print 32)) 20 32

  13. Tipos de variables • A la vista de los alcances léxico y dinámico comentados anteriormente diferenciamos los siguientes tipos de variables: • Locales • Su alcance es el del contexto en que se definen • implícitamente poseen alcance léxico • Globales • Se definen con setf (usar defparameter en archivos de código fuente) • Son visibles en cualquier lugar • Poseen alcance dinámico, implícitamente son special • Por convenio se denotan entre asteriscos • Libres • Se denomina a aquellas variables que se definen fuera de la función que las referencia (x en el ejemplo) > (setf fn (let ((i 3)) #’(lambda (x) (+ x i)))) > (funcall fn 2) 5 • Se pueden declarar (declare para local, declaim para global), tipos (type) de variables con propósitos de eficiencia de compilación (Graham 13.3).

  14. A-listas. Pattern-matching. • Mediante EQUAL comparamos datos para ver si tienen la misma estructura >(EQUAL ‘(* pi (expt r 2) h) ‘(* pi (expt r 2) h)) T • EQUAL no puede comparar expresiones que tengan partes constantes y partes variables. Supongamos, por ejemplo, la función match: >(match ‘(a b c) ‘(a b ?v)) ((?v c)) >(match ‘(a c c) ‘(a b ?v)) nil • Observamos que se crea una ligadura variable-valor entre los términos que coincidan • Para conseguir este efecto utilizaremos las listas de asociación (a-listas) que sirven para comparar expresiones (patrones). • A-listas • Son listas formadas por listas anidadas • Cada sublista posee • Una llave (el CAR) • Un dato (el CDR) • ((?padre Juan) (?hijo José)) • Para explorar una a-lista utilizamos ASSOC. > (assoc :padre ((:padre Juan) (:hijo José))) (:padre Juan) > (assoc :abuelo ((:padre Juan) (:hijo José))) Nil

  15. MOD NP N BV ADV DET DET 2 3 4 6 1 5 DET ADJ 7 MOD 8 ADJ N CNJ 9 CNJ Ejemplo de uso de assoc en NLP, (1) • La siguiente FSTN (Finite State Transition Network) permite reconocer oraciones en inglés como “A man is a consumer and often very very stupid” • NP: kim, sandy, lee • DET: a, the, her • N: consumer, man, woman • BV: is, was • CNJ: and, or • ADJ: happy, stupid • MOD: very • ADV: often, always, • Sometimes • #: “jump”

  16. Ejemplo de uso de assoc en NLP, (2) • Definimos la asignación siguiente como representación de la red anterior (setf english ‘((:Initial (1)) (:Final (9)) (From 1 to 3 by NP) (From 1 to 2 by DET) (From 2 to 3 by N) (From 3 to 4 by BV) (From 4 to 5 by ADV) (From 4 to 5 by |#|) (From 5 to 6 by DET) (From 5 to 7 by DET) (From 5 to 8 by |#|) (From 6 to 6 by MOD) (From 6 to 7 by ADJ) (From 7 to 9 by N) (From 8 to 8 by MOD) (From 8 to 9 by ADJ) (From 9 to 4 by CNJ) (From 9 to 1 by CNJ)))

  17. Ejemplo de uso de assoc en NLP, (3) • Las funciones siguientes nos permiten acceder a los elementos descriptores de la red (inicio, fin y transiciones) (defun initial-nodes (network) (nth 1 (assoc :Initial network))) (defun initial-nodes (network) (nth 1 (assoc :Final network))) (defun transitions (network) (cddr network)) • Las transiciones tienen la estructura de la lista • (From <node> to <newnode> by <label>) Ejercicio propuesto: Dado un nodo, obtener la lista de sus destinos <newnode> y etiquetas <label>. Ejemplo: > (nodo 1 red) ((3 NP) (2 DET))

  18. Ejemplo de uso de assoc Match I, (1) • Podemos, por ejemplo, usar ASSOC para construir una función que haga comparación de patrones. (defun match (pattern data bindings) ;; caso base: pattern es un átomo (cond ((atom pattern) (if (variablep pattern) (psble-bind pattern data bindings) (if (equal pattern data) bindings ‘fallo))) ;; caso base: pattern no es un átomo y data sí ((atom data) ‘fallo) ;; caso recursivo (t (let ((car-bind (match (car pattern) (car data) bindings))) (if (eq car-bind ‘fallo) ‘fallo (match (cdr pattern) (cdr data) car-bind))))))

  19. Ejemplo de uso de assoc Match II, (2) (defun psble-bind (var data bindings) (let ((ligaduras (assoc var bindings))) (if (null ligaduras) ;; si la variable no está ligada ;; añadimos una ligadura nueva (cons (list var data) bindings) ;; la variable ligada y el dato deben coincidir ;; caso contrario: fallo (if (equal (valor-bind ligaduras) data) bindings ‘fallo)))) (defun valor-bind (lista-variable-valor) ;; función de acceso al valor de los elementos ;; de la lista (second lista-variable-valor)) (defun variablep (v) ;; comprueba si pattern es una variable (and (symbolp v) (char= (char (symbol-name v) 0) #\?)))

  20. Aplicación de match: reescritura de programas • Supongamos que deseamos convertir determinado código Lisp. Disponemos de las siguientes reglas de reescritura: lhs ->rhs • (1+ ?x) -> (+ 1 ?x) • (list ?x) -> (cons ?x nil) • (second ?x) -> (cadr ?x) • (cadr ?x) -> (car (cdr ?x)), etc. • lhs representa una expresión Lisp y rhs representa una expresión equivalente. • La expresión • (second *registros*) • hará match con lhs de regla 3 y se reescribirá como • (cadr *registros*) • que hará match con lhs de regla 4 obteniendo • (car (cdr *registros*)) • Con (SUBST new old list) podemos aplicar las reglas de sustitución necesarias cuando se verifica match. • (setf form ‘(car (cdr (?x))) (car (cdr ?x)) • (subst ‘(padre Juan Carlos) ‘?x form) (car (cdr (padre Juan Carlos)))

More Related