Está en la página 1de 7

LISP I

Programacin recursiva frente a iterativa


Caractersticas de la programacin recursiva:
Implementacin intuitiva y elegante. La traduccin de la solucin recursiva de un problema (caso base y caso recursivo) a cdigo Lisp es prcticamente inmediata. til para optimizar clculos. Las estructuras de datos en Lisp hacen un uso implctito de los punteros, como en las listas:
NIL Un cons cuyo cdr es, a su vez, una lista

til cuando hay varios niveles de anidamiento. La solucin para un nivel es vlida para el resto.

Formas de hacer versin iterativa:


Con mapcar Con bucles (dolist, dotimes, etc. Desaconsejado).

Ejemplos de recursividad, (1)


Ejemplo del clculo de la potencia de un nmero optimizada
> (defun potencia (x n) ;; Optimizacion calculo potencia" (cond ((= n 0) 1) ((evenp n) (expt (potencia x (/ n 2)) 2) ) (t (* x (potencia x (- n 1)))))) > (potencia 2 3) 8

La interpretacin y comprensin del cdigo es compleja. Por ello es importante llegar a un compromiso entre la claridad de la programacin y la eficiencia en la misma.
3

Ejemplos de recursividad, (2)


Contar los tomos de cualquier expresin LISP:
> (cuenta-atomos '(a (b c) ((d e) f))) 6 > (defun cuenta-atomos (expr) (cond ((null expr) 0) ((atom expr) 1) (t (+ (cuenta-atomos (first expr)) (cuenta-atomos (rest expr))))))

Ejemplos de recursividad, (3)


Aplanar una lista:
(aplana (a (b c) ((d e) f))) >>> (A B C D E F)
> (defun aplana (lista) (cond ((null lista) NIL) ((atom (first lista)) (cons (first lista) (aplana (rest lista)))) (t (append (aplana (first lista)) (aplana (rest lista))))))

Ejemplos de recursividad, (4)


Nmero de sublistas de una lista (nmero de veces que se abre parntesis, menos 1):
(sublistas (a (b c) ((d e) f))) >>> 3
> (defun sublistas (expresion) (cond ((or (null expresion) (atom expresion)) 0) (t (+ (if (atom (first expresion)) 0 1) (sublistas (first expresion)) (sublistas (rest expresion))))))

Ejemplos de recursividad, (5)


Producto escalar:
(producto '(2 3) '(4 5)) >>> 23 2 x 4 + 3 x 5 = 23

Versiones vlidas:
Versin recursiva:
> (defun producto (vector1 vector2) (if (or (null vector1) (null vector2)) 0 (+ (* (first vector1) (first vector2)) (producto (rest vector1) (rest vector2)))))

Versin con mapcar


>(defun producto (vector1 vector2) (apply #'+ (mapcar #'* vector1 vector2)))

Ejemplos de recursividad, (6)


Versin no vlida del producto escalar:
Versin iterativa (no recomendable):
> (defun producto (vector1 vector2) (let ((suma 0)) (dotimes (i (length vector1)) (setf suma (+ suma (* (nth i vector1) (nth i vector2))))) suma))

Ejemplos de recursividad, (7)


> (defun profundidad-maxima (expresion) (cond ((null expresion) 0) ((atom expresion) 1) (t (+ 1 (apply #'max (mapcar #'profundidad-maxima expresion)))))) >>> PROFUNDIDAD-MAXIMA > (profundidad-maxima '(1)) >>>> 2 > (profundidad-maxima '((1 (2 (3))) 4)) >>>> 5

Repaso de operadores, (1)


Recordemos los siguientes operadores:
COUNT-IF, FIND-IF, REMOVE-IF, REMOVE-IF-NOT, DELETE-IF, DELETE-IF-NOT COUNT / COUNT-IF
Contar apariciones: (count <elemento> <lista>

[:test <fun-igualdad>]) (count 2 (1 2 3 4 2 4 5 2)) 3


Contar los elementos que cumplen /no cumplen una condicin de una lista (count-if[-not] <predicado><lista>

(count-if oddp (1 2 3 4 5 6)) 3


10

Repaso de operadores, (2)


FIND / FIND-IF
Devuelve la primera aparicin: (find <elemento> <lista>

[:test <fun-igualdad>]) (find 2 (1 2 3 4 2 4 5 2)) 2


Devuelve el primer elemento que cumple/o no cumple el predicado (find-if[-not] <predicado><lista>

(find-if oddp '(1 2 3 4 2 4 5 2)) 1 REMOVE / REMOVE-IF


Borrar las apariciones de un elemento indicado (remove <elemento> <lista>

[:test <fun-igualdad>]) (remove 2 (1 2 3 4 2 4 5 2)) (1 3 4 4 5)


Elimina los que cumple/o no cumple el predicado (remove-if[-not] <predicado><lista>

(remove-if oddp '(1 2 3 4 2 4 5 2)) (2 4 2 4 2)

11

Ejemplos de recursividad, (8)


Objetivo: sin utilizar remove-if, conseguir la misma funcionalidad del operador:
(quitar-si evenp '(1 2 3 4)) (1 3)

Versiones vlidas:
Versin recursiva:
(defun quitar-si (predicado lista) (cond ((null lista) nil) ((funcall predicado (car lista)) (quitar-si predicado (cdr lista))) (t (cons (car lista) (quitar-si predicado (cdr lista))))))

Versin con mapcar


(defun quitar-si (predicado lista) (delete NIL (mapcar #'(lambda (elemento) (when (not (funcall predicado elemento)) elemento)) lista)))

12

Ejemplos de recursividad, (9)


Recorriendo la lista con dolist:
(defun QUITAR-SI (predicado lista) (let (listaaux) (dolist (i lista listaaux) (if (not (eval (list predicado i))) (setf listaaux (append listaaux (list i)))
) ) ) )

13

Ejemplos de recursividad, (10)


Versin errnea:
Mal uso de mapcar. El hecho de que hagamos uso de mapcar no garantiza la correccin del cdigo programado.
(defun QUITAR-SI2 (predicado lista) (mapcar #(lambda (elemento) (if (apply predicado (list elemento)) (remove elemento lista)) ) lista))
> (QUITAR-SI2 'evenp '(1 2 3 4)) (NIL (1 3 4) NIL (1 2 3))

14