Vous êtes sur la page 1sur 26

Resolviendo problemas en Haskell

Rosana Matuk y Gabriela Steren

28 de Agosto de 2012

M
as problemas con listas

Otras estructuras de datos

Ejercicio 1
Sea el siguiente tipo: type Punto = (Int,Int)
Definir, usando listas por comprensi
on, una lista (infinita)
puntosDelPlano::[Punto] que contenga todos los puntos del
cuadrante superior derecho del plano.
Atenci
on: la funci
on debe garantizar que eventualmente todo punto del
cuadrante superior derecho ser
a listado. Una forma de garantizar esto es
recorrer los puntos siguiendo las diagonales x + y = k, con k = 0, 1, 2, 3, . . .

Ejemplo: [(0,0), (0,1), (1,0), (0,2), (1,1), (2,0), (0,3), (1,2),


(2,1), (3,0), (0,4),...]

M
as problemas con listas

Otras estructuras de datos

Soluciones

Soluci
on 1
puntosDelPlano :: [Punto]
puntosDelPlano = [(x, y) | k <-[0..], x <-[0..k], y <-[0..k],
x + y == k]

Soluci
on 2
puntosDelPlano :: [Punto]
puntosDelPlano = [(x,k-x) | k<-[0..], x<-[0..k]]

M
as problemas con listas

Otras estructuras de datos

Ejercicio 2

Escribir la funcion listasQueSuman::Int->[[Int]] que, dado


un n
umero natural n, devuelve todas las listas de enteros positivos1
cuya suma sea n.
Para este ejercicio se permite usar recursi
on explcita.
Soluci
on
listasQueSuman::Int->[[Int]]
listasQueSuman 0 = [[]]
listasQueSuman n | n > 0 = [(x:xs) | x<-[1..n],
xs<-listasQueSuman (n-x)]

Es decir, mayores o iguales que 1

M
as problemas con listas

Otras estructuras de datos

Ejercicio 3

Definir en Haskell una lista que contenga todas las listas finitas de
enteros positivos (esto es, con elementos mayores o iguales que 1).
No debe haber listas repetidas.
Soluci
on
listasPositivas::[[Int]]
listasPositivas = [xs | n<-[0..], xs<-listasQueSuman n]

M
as problemas con listas

Otras estructuras de datos

Ejemplo: esquema de recursion para listas

Definir en Haskell la funci


on zip sin usar recursi
on explcita.
zip
zip
zip
zip

:: [a] -> [b] -> [(a,b)]


[] ys = []
(x:xs) [] = []
(x:xs) (y:ys) = (x,y):(zip xs ys)

Recursion sobre dos listas a la vez... es feo y confuso.


Podemos mejorarla?

M
as problemas con listas

Otras estructuras de datos

Ejemplo: esquema de recursion para listas

Definir en Haskell la funci


on zip sin usar recursi
on explcita.
zip = foldr
(\x rec lista -> case lista of
[] -> []
(y:ys) -> (x,y):(rec ys))
(const [])

Recordemos...
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f z [] = z
foldr f z (x:xs) = x f (foldr f z xs)
foldr op z (a1 : (a2 : (a3 : []))) =
a1 op (a2 op (a3 op z ))

M
as problemas con listas

Otras estructuras de datos

Ejemplo: esquema de recursion para listas (cont.)

foldl op b (a1 : (a2 : (a3 : []))) =


((b op a1) op a2) op a3
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
Que hace foldl (flip (:)) []?
Tambien son u
tiles las variantes para listas no vacas: foldr1 y
foldl1.

M
as problemas con listas

Otras estructuras de datos

Ejercicio 4

Sea el siguiente tipo:


data AB a = Hoja a | Bin (AB a) a (AB a)
Ejemplo: mi
Arbol = Bin (Hoja 3) 5 (Bin (Hoja 7) 8 (Hoja 1))

Definir el esquema de recursi


on estructural (fold) para arboles
binarios, y dar su tipo.
El esquema debe permitir definir las funciones altura, ramas,
#nodos, #hojas, espejo, etc.

M
as problemas con listas

Otras estructuras de datos

Como hacemos?

Recordemos el tipo de foldr, el esquema de recursion estructural


para listas.
foldr :: (a -> b -> b) -> b -> [a] -> b
Por que tiene ese tipo?
(Pista: pensar en cu
ales son los constructores del tipo [a]).

Un esquema de recursi
on estructural espera recibir un argumento
por cada constructor (para saber que devolver en cada caso), y
ademas la estructura que va a recorrer.
El tipo de cada argumento va a depender de lo que reciba el
constructor correspondiente. (Y todos van a devolver lo mismo!)

M
as problemas con listas

Otras estructuras de datos

Como hacemos? (Continua)

Miremos bien la estructura del tipo.

Estamos ante un tipo inductivo con un constructor no recursivo y


un constructor recursivo.
Cual va a ser el tipo de nuestro fold?
Y la implementacion?

M
as problemas con listas

Otras estructuras de datos

Solucion

foldAB::(a->b)->(b->a->b->b)->AB a -> b
foldAB fHoja (Hoja n)
= fHoja n
foldAB fHoja fBin (Bin t1 n t2)
= fBin (foldAB fHoja fBin t1)
n (foldAB fHoja fBin t2)

Ejercicio para ustedes: definir las funciones altura, ramas,


#nodos, #hojas y espejo usando foldAB.
Si quieren podemos hacer alguna en el pizarr
on.

M
as problemas con listas

Otras estructuras de datos

Ejercicio 5

Definir el esquema de recursi


on estructural para el siguiente tipo:
data Num a=>Polinomio a

=
|
|
|

X
Cte a
Suma (Polinomio a) (Polinomio a)
Prod (Polinomio a) (Polinomio a)

Luego usar el esquema definido para escribir la funcion:


evaluar::Num a=>a->Polinomio a->a

M
as problemas con listas

Otras estructuras de datos

Solucion

foldPoli::Num a=>b->(a->b)->(b->b->b)->(b->b->b)->Polinomio a->b


foldPoli casoX casoCte casoSuma casoProd pol = case pol of
X -> casoX
Cte n -> casoCte n
Suma p q -> casoSuma (rec p) (rec q)
Prod p q -> casoProd (rec p) (rec q)
where rec = foldPoli casoX casoCte casoSuma casoProd
evaluar::Num a=>a->Polinomio a->a
evaluar n = foldPoli n id (+) (*)

M
as problemas con listas

Otras estructuras de datos

Algo un poco mas complejo... o no?


1

Definir el tipo de datos RoseTree de arboles no vacos, donde


cada nodo tiene una cantidad indeterminada de hijos.

Escribir el esquema de recursi


on estructural para RoseTree.
Es importante escribir primero su tipo.
Usando el esquema definido, escribir las siguientes funciones:

hojas, que dado un RoseTree, devuelve una lista con sus


hojas ordenadas de izquierda a derecha, seg
un su aparicion en
el RoseTree.
distancias, que dado un RoseTree, devuelve las distancias de
su raz a cada una de sus hojas.
altura, que devuelve la altura de un RoseTree (la cantidad de
nodos de la rama mas larga). Si el RoseTree es una hoja, se
considera que su altura es 1.
cantNodos, que devuelve la cantidad total de nodos del
RoseTree.

M
as problemas con listas

Tipo RoseTree

data RoseTree a = Rose a [RoseTree a]


Como hacemos el fold?
Hay caso/s base?
Cuantos llamados recursivos hay que hacer?

Otras estructuras de datos

M
as problemas con listas

Otras estructuras de datos

Empecemos por el tipo

Recordar: un fold siempre toma un argumento por cada


constructor del tipo, y ademas la estructura que va a recorrer.
Los argumentos que corresponden a los constructores devuelven
siempre algo del tipo que queremos devolver, y reciben tantos
argumentos como sus respectivos constructores.
Si el constructor es recursivo, el argumento correspondiente del
fold va a recibir el resultado de cada llamada recursiva.

M
as problemas con listas

Otras estructuras de datos

Como se aplica esto al RoseTree?

data RoseTree a = Rose a [RoseTree a]

En el caso del RoseTree, eso no cambia. Si nuestro constructor


toma una lista de RoseTrees, tendremos una lista de resultados de
las recursiones.
Entonces el tipo del fold es...
foldRT::(a->[b]->b)->RoseTree a->b

M
as problemas con listas

Otras estructuras de datos

Ahora implementemoslo

foldRT::(a->[b]->b)->RoseTree a->b
foldRT f (Rose x hs) = f x (map (foldRT f) hs)

M
as problemas con listas

Otras estructuras de datos

Y finalmente...
1

Definir el tipo de datos RoseTree de arboles no vacos, donde


cada nodo tiene una cantidad indeterminada de hijos. X

Escribir el esquema de recursi


on estructural para RoseTree.
Es importante escribir primero su tipo. X
Usando el esquema definido, escribir las siguientes funciones:

hojas, que dado un RoseTree, devuelve una lista con sus


hojas ordenadas de izquierda a derecha, seg
un su aparicion en
el RoseTree.
distancias, que dado un RoseTree, devuelve las distancias de
su raz a cada una de sus hojas.
altura, que devuelve la altura de un RoseTree (la cantidad de
nodos de la rama mas larga). Si el RoseTree es una hoja, se
considera que su altura es 1.
cantNodos, que devuelve la cantidad total de nodos del
RoseTree.
espejo, analogo al de arbol binario.

M
as problemas con listas

Otras estructuras de datos

Soluciones (prueben resolverlo primero)


cantNodos::RoseTree a->Int
cantNodos = foldRT (\ rs->1+(sum rs))
espejo::RoseTree a->RoseTree a
espejo = foldRT (\x rs-> Rose x (reverse rs))
hojas::RoseTree a->[a]
hojas = foldRT (\x rs->if (null rs) then [x] else concat rs)
distancias :: RoseTree a -> [Int]
distancias = foldRT (\x rs->if (null rs) then [0] else map (+1) (concat rs))

altura::RoseTree a->Int
altura = foldRT (\x rs->if (null rs) then 1 else 1+(maxlista rs))
where maxlista = foldr1 max
O, alternativamente...
altura = (+1).maxlista.distancias where maxlista = foldr1 max
(La lista de distancias nunca es vaca, as que podemos usar foldr1.)

M
as problemas con listas

Otras estructuras de datos

Estructuras de datos con funciones

Se tiene el siguiente tipo de datos para definir arboles con claves:


data AC a c = Kin a (c -> AC a c) | Nil
donde a es el tipo de datos de los elementos del arbol, y la funcion
c -> AC a c define los hijos de un arbol; es decir, para cada clave
de tipo c, la funcion retorna el arbol hijo que le corresponde.
Definir el esquema de recursi
on estructural para los arboles
con claves utilizando recursi
on explcita.
Utilizando foldAC definir la funci
on mapAC, que tome una
funcion y la aplique sobre cada elemento de un arbol con
claves.

M
as problemas con listas

Otras estructuras de datos

Definiendo el fold para el arbol con claves

foldAC :: b -> (a -> (c -> b) -> b) -> AC a c -> b


foldAC cb fRec ab = case ab of
Nil -> cb
Kin e fHijos -> fRec e (rec.fHijos)
where rec = foldAC cb fRec

M
as problemas con listas

...Y ahora el map

mapAC :: (a->b) -> AC a c -> AC b c


mapAC f = foldAC Nil (\e r -> Kin (f e) r)
O tambien:
mapAC f = foldAC Nil (\e -> Kin (f e))
O:
mapAC f = foldAC Nil (Kin . f)

Otras estructuras de datos

M
as problemas con listas

Otro ejercicio... sin fold!

Otras estructuras de datos

Fin (por ahora)

? ?

? ?

? ? ? ? ? ? ?

Vous aimerez peut-être aussi