Professional Documents
Culture Documents
Listas y Strings
Listas
Las listas es el tipos de datos predefinido mas desarrollado en Haskell. Una lista es una secuencia de 0 o ms elementos de un mismo tipo. [T] es el tipo de las listas de elementos de tipo T, donde T puede ser cualquier expresin de tipo incluyendo variables (polimorfismo).
Su definicin es equivalente a
data List a = Empty | Cons [a] [] (:) a (List a)
Prelude> :i : infixr 5 : (:) :: a -> [a] -> [a] data [a] = [] | a : [a]
-- data constructor
est enriquecido con algunas otras funciones monomrficas. "c1c2...cn" es una abreviatura de ['c1','c2',..., 'cn' ].
- 124 -
Show [a] tambin requiere Show a y sirve para mostrar 1:2:3:[] de la forma [1,2,3] (sta no es la que se generara con deriving).
Ord [a] tambin requiere Ord a y define orden lexicogrfico.
- 125 -
Cal debe ser el resultado de evaluar las siguientes expresiones? 1) [1,2] < [1,7,6] 2) [5,1] < [5] 3) "casa" < "campo" 4) "cas" < "casa 5) ["campo", "perro"] < ["country, "dog"]
- 126 -
Los patrones bsicos para listas son: [] y x:xs Definir inductivamente una funcin f sobre listas consiste en definir su valor para [] f .. [] .. = ..... para una lista x:xs en base al valor de (f .. xs ..) f .. (x:xs) .. = .. (f .. xs ..) .. Pero los patrones se pueden anidar (sin repetir variables): [],(x,y):ps [], [x], x:y:xs etc
- 127 -
Ejemplo: sumapares :: Num a => [(a,a)] -> [a] sumaPares [] = [] sumaPares ((x,y):xs) = (x+y):(sumapares xs) de modo que sumaPares [(1,9),(37,8)] [10,45] sumaPares [(2,3.5),(1.2,3.3)] [5.5,4.5]
- 128 -
init:: [a] -> [a] init [x] = [] init (x:xs) = x : init xs null:: [a] -> Bool null [] = True null (_:_) = False
-- funcin parcial
infixr 5 ++ (++) :: [a] -> [a] -> [a] [] ++ ys = ys (x:xs) ++ ys = x : (xs ++ ys)
- 130 -
infixl 9 !! (!!) :: [a] -> Int -> a -- Indexacin de listas: xs !! n es el n-simo elemento de xs -- Induccin sobre los naturales
xs [] (x:_) (_:xs)
!! !! !! !!
n | n<0 = error "Prelude.!!: negative index" _ = error "Prelude.!!: index too large" 0 = x n = xs !! (n-1)
Hugs> [] !! 3 Program error: Prelude.!!: index too large Hugs> "abc" !! 3 Program error: Prelude.!!: index too large
- 131 -
Listas intensionales
Tambin se llaman listas ZF (Zermelo-Frankling) Su definicin es [<expr> | <cualif>_1, <cualif>_2, ..., <cualif>_n] donde cada cualificador <cualif>_i puede ser de dos tipos: generador: <patrn> <- <expresin> Ejemplo: [x*x | x <- [1..10]] [1,4,9,16,25,36,49,64,81,100] filtro: <expresin booleana>
Combinacin de cualificadores
Se pueden combinar varios generadores [(x,y) | x <-[1..3], y <-[1..2]] [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2)] Los cualificadores (generadores o filtros) pueden usar los valores generados por generadores previos [(x,y) | x <-[1..3], y <-[1..x]] [(1,1),(2,1),(2,2),(3,1),(3,2),(3,3)] [(x,y) | x <- [1..3], y <-[1..x], even x || even y ] [(2,1),(2,2),(3,2)]
- 133 -
[5.5,10.0,4.5]
sumaParesOrd :: Num a => [(a,a)] -> [a] sumaParesOrd ps = [x+y | (x,y) <- ps , x<y] sumaParesOrd [(1,9),(37,8)] [10] sumaParesOrd [(2,3.5),(7,3),(1.2,3.3)]
[5.5,4.5]
- 134 -
quicksort :: Ord a => [a] -> [a] -- (quicksort xs) ordena no-decreciente la lista xs quicksort [ ] = [ ] quicksort (x:xs) = quicksort [y | y<-xs, y<x] ++ [x] ++ quicksort [y | y<-xs, y>=x] divisores :: Integral a => a -> [a] divisores x = [z | z <- [1..x`div`2], mod x z == 0] ++ [x] divisores 25 [1,5,25] divisores 43 [1,43] divisores 13467 => [1,3,67,201,4489,13467]
- 135 -
- 137 -
La funcin zip
zip:: [a] -> [b] -> [(a,b)] zip (x:xs) (y:ys) = (x,y): zip xs ys zip _ _ = []
- 138 -
En Prelude.hs su definicin hace uso de una funcin ms general: zipWith:: (a->b->c) -> [a]->[b]->[c] zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys zipWith _ _ _ = [] zip:: [a] -> [b] -> [(a,b)] zip = zipWith (\x y -> (x,y))
Funcin que obtiene la lista de todas las posiciones en la que aparece un elemento x (dado) en una lista dada: posiciones:: a =>[a]->[Int] posiciones x xs = [i| (y,i)<-zip xs [0..] , y==x] Funcin que obtiene la primera posicin o un (-1) si el elemento no est primpos:: a =>[a]-> Int primpos x xs = head (posiciones x xs ++ [-1])
- 140 -
False
- 141 -
sum [x1,x2,...,xn] = x1 + x2 + ... + xn (+0) funcin : (+) elemento neutro: 0 and [b1,b2,...,bn] = b1 && b2 && ... && bn (&& True) funcin : (&&) elemento neutro: True concat [xs1,xs2,...,xsn] = xs1 ++ xs2 ++ ... ++ xsn (++[]) funcin : (++) elemento neutro: []
- 142 -
foldr ( ) e [x1,x2,...,xn] = x1
(x2
...(xn
e)...)
foldr:: (a -> b -> b) -> b -> [a] -> b foldr f e [] = e foldr f e (x:xs) = f x (foldr f e xs) concat:: [[a]] -> [a] concat = foldr (++) [] and, or:: [Bool] -> Bool and = foldr (&&) True or = foldr (||) False sum, product:: Num a => [a] -> a sum = foldr (+) 0 product = foldr (*) 1
- 143 -
- 144 -
foldr1
para listas no vacas (no precisa elemento neutro): foldr1 ( ) [x1,x2,...,xn] = x1 ( x2 ...(x(n-1)
xn)...)
foldr1:: (a -> a -> a) -> [a] -> a foldr1 f [x] = x foldr1 f (x:xs) = f x (foldr1 f xs) Ahora podemos redefinir maxlista como: maximum :: Ord a => [a] -> a maximum = foldr1 max
-- es predefinida
- 146 -
= 10*(...(10*0 + d0)+...)+ dn-1) + dn = (... ((0 d0) d1) ... dn-1) dn siendo x y = 10*x + y foldl ( ) e [x1,x2,...,xn] = (...((e x1)
x2)....)
xn
foldl:: (a -> b -> a) -> a -> [b] -> a foldl f e [] = e foldl f e (x:xs) = foldl f (f e x) xs Cuando la operacin con la que se pliega es asociativa y tiene elemento neutro es equivalente usar foldl o foldr: concat = foldl (++) [] and = foldl (&&) True or = foldl (||) False sum = foldl (+) 0 product = foldl (*) 1
- 148 -
instance Visible a => Visible [a] where toString= concat. map toString size = foldr (+) 0 . map size supuesto que class Visible a where toString:: a -> String size:: a -> Int size x = length (toString x)
Curso 2010-11
- 150 -
sublists :: [a] -> [[a]] sublists xs = [take n xs | n<-[0..length xs]] sublists [1,2,3,4] [[],[1],[1,2],[1,2,3],[1,2,3,4]] drop:: drop n drop _ drop n Int -> [a] -> [a] xs | n <= 0 = xs [] = [] (_:xs) = drop (n-1) xs
- 151 -
splitAt:: Int -> [a] -> ([a], [a]) Definicin intuitiva: splitAt n xs = (take n xs, drop n xs) Para no recorrer dos veces la lista, su definicin es: splitAt n xs | n <= 0 = ([],xs) splitAt _ [] = ([],[]) splitAt n (x:xs) = (x:xs',xs'') where (xs',xs'') = splitAt (n-1) xs
- 152 -
- 153 -
span:: (a -> Bool) -> [a] -> ([a],[a]) span p [] = ([],[]) span p (x:xs) | p x = (x:ys, zs) | otherwise = ([],x:xs) where (ys,zs) = span p xs que es una forma ms eficiente que: span p xs = (takeWhile p xs, dropWhile p xs) break:: (a -> Bool) -> [a] -> ([a],[a]) break p = span (not . p)
- 154 -
quicksort
"Eaaacceeeeeilllmmmnnnnnnooorrsstttu"
group
["E","aaa","cc","eeeee","i","lll","mmm","nnnnnn","ooo", "rr","ss","ttt","u","",""]
listaMasLarga
"nnnnnn"
head
'n'
- 155 -
Agrupar en sublistas
group:: Eq a => [a] -> [[a]]
-- group xs divide xs en sublistas de elementos consecutivos -- iguales, por ejemplo: group "Mississippi" -=> ["M","i","ss","i","ss","i","pp","i"]
group
groupBy (==)
= =
Secuencias aritmticas
[n..] es la lista [n,n+1,n+2,... [n..m] es la lista [n,n+1,n+2,...,limit] siendo limit el menor nmero (entero o real) mayor o igual que m.
[5..8]
[5,6,7,8]
[5.7,6.7,7.7,8.7] []
[5.7..8.2] [2..(-3.1)]
[1,1,1,...
[n,m..m] es la lista [n,m,m+i,m+2*i,...,limit] siendo i= m-n limit = mayor nmero (entero/real) menor o igual que m.
Hugs> [1,3..8]
[1,3,5,7] Hugs> [1,-3..(-14)]
Hugs> [1,3..9]
[1,3,5,7,9] Hugs> [1,-3..(-11)]
[1,-3,-7,-11]
Hugs> [1,1..8] [1,1,1,...
[1,-3,-7,-11]
Hugs> [1.5,1.5..8.5] [1.5,1.5,1.5,...
- 159 -
Todo tipo T que sea instancia de la clase Enum cuenta con los mtodos succ y pred, que hacen las veces de (+1) y (-1) respectivamente para construir secuencias de elementos de tipo T data Prueba = A | B | C | D | E | F deriving (Show,Enum)
[C..] [C,D,E,F] [A..D] [A,B,C,D] [A,B..] [A,B,C,D,E,F] [F,D..] [F,D,B]
- 160 -
Hay que colorear un mapa, de forma que las provincias vecinas nunca coincidan en el color
- 161 -
data Color = Rojo | Verde | Azul deriving (Show,Enum,Eq) data Provincia = Almeria | Cadiz | Cordoba | Granada | Jaen | Huelva | Malaga | Sevilla deriving (Show,Enum,Eq) type Frontera = Provincia -> [Provincia]
- 162 -
frontera p = case p of Almeria -> [Granada] Cadiz -> [Huelva,Sevilla,Malaga] Cordoba -> [Sevilla,Malaga,Jaen,Granada] Granada -> [Malaga,Cordoba,Jaen,Almeria] Jaen -> [Cordoba,Granada] Huelva -> [Cadiz,Sevilla] Malaga -> [Cadiz,Sevilla,Cordoba,Granada] Sevilla -> [Huelva,Cadiz,Malaga,Cordoba] data Mapa = Atlas [Provincia] Frontera andalucia :: Mapa andalucia = Atlas [Almeria .. Sevilla] frontera
- 163 -
colorFras :: Provincia -> [(Provincia,Color)] -> Frontera -> [Color] -- (colorFras prov provcol fra) devuelve la lista de -- todos los colores de las provincias que son fronteras -- de prov segn provCol y fra colorFras prov provCol fra = [col'| (prov',col')<- provCol, elem prov' (fra prov)]
- 164 -
solsColorear :: (Mapa,[Color]) -> [[(Provincia,Color)]] -- "solsColorear(mapa, colores)" da la lista de todas las -- formas posibles de colorear mapa usando colores solsColorear ((Atlas [] _), colores) = [[]]
solsColorear ((Atlas (prov:restoprov) fra), colores) = [(prov,color):restoMapa | restoMapa <- solsColorear ((Atlas restoprov fra), colores), color <- diff colores (colorFras prov restoMapa fra)] where diff xs ys = [x | x <- xs, notElem x ys]
- 165 -
colorear:: (Mapa,[Color]) -> [(Provincia,Color)] colorear = head . solsColorear sol1 = colorear (andalucia, [Rojo .. Azul]) sol2 = colorear (andalucia, [Rojo,Verde]) Main> sol1 [(Almeria,Verde),(Cadiz,Azul),(Cordoba,Azul),(Granada,Rojo ),(Jaen,Verde),(Huelva,Verde),(Malaga,Verde),(Sevilla,Rojo )]
- 166 -