Ej Prog Haskell

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 109

Ejercicios de programacin funcional con Haskell

Jos A. Alonso Jimnez

Grupo de Lgica Computacional Dpto. de Ciencias de la Computacin e Inteligencia Articial Universidad de Sevilla Sevilla, 8 de Agosto de 2007 (Versin de 20 de septiembre de 2007)

2 Esta obra est bajo una licencia ReconocimientoNoComercialCompartirIgual 2.5 Spain de Creative Commons.

Se permite: copiar, distribuir y comunicar pblicamente la obra hacer obras derivadas Bajo las condiciones siguientes: Reconocimiento. Debe reconocer los crditos de la obra de la manera especicada por el autor. No comercial. No puede utilizar esta obra para nes comerciales. Compartir bajo la misma licencia. Si altera o transforma esta obra, o genera una obra derivada, slo puede distribuir la obra generada bajo una licencia idntica a sta. Al reutilizar o distribuir la obra, tiene que dejar bien claro los trminos de la licencia de esta obra. Alguna de estas condiciones puede no aplicarse si se obtiene el permiso del titular de los derechos de autor.

Esto es un resumen del texto legal (la licencia completa). Para ver una copia de esta licencia, visite http://creativecommons.org/licenses/by-nc-sa/2.5/es/ o envie una carta a Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

ndice general
1. Introduccin a la programacin funcional 1.1. Factorial . . . . . . . . . . . . . . . . . . 1.2. Nmero de combinaciones . . . . . . . . 1.3. Comprobacin de nmero impar . . . . 1.4. Cuadrado . . . . . . . . . . . . . . . . . 1.5. Suma de cuadrados . . . . . . . . . . . . 1.6. Raices de ecuaciones de segundo grado 1.7. Valor absoluto . . . . . . . . . . . . . . . 1.8. Signo . . . . . . . . . . . . . . . . . . . . 1.9. Conjuncin . . . . . . . . . . . . . . . . . 1.10. Anterior de un nmero natural . . . . . 1.11. Potencia . . . . . . . . . . . . . . . . . . 1.12. Funcin identidad . . . . . . . . . . . . . 7 7 9 10 11 12 13 13 14 15 15 16 17 19 20 20 21 22 23 23 24 25 26 27 27 28 29 30 30 31

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

2. Nmeros y funciones 2.1. Casi igual . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2. Siguiente de un nmero . . . . . . . . . . . . . . . . . . 2.3. Doble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4. Mitad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5. Inverso . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6. Potencia de dos . . . . . . . . . . . . . . . . . . . . . . . 2.7. Reconocimiento de nmeros positivos . . . . . . . . . . 2.8. Aplicacin de una funcin a los elementos de una lista 2.9. Filtrado mediante una propiedad . . . . . . . . . . . . . 2.10. Suma de los elementos de una lista . . . . . . . . . . . . 2.11. Producto de los elementos de una lista . . . . . . . . . . 2.12. Conjuncin sobre una lista . . . . . . . . . . . . . . . . . 2.13. Disyuncin sobre una lista . . . . . . . . . . . . . . . . . 2.14. Plegado por la derecha . . . . . . . . . . . . . . . . . . . 2.15. Plegado por la izquierda . . . . . . . . . . . . . . . . . . 2.16. Resultados acumulados . . . . . . . . . . . . . . . . . . 3

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

4 2.17. 2.18. 2.19. 2.20. 2.21. 2.22. 2.23. 2.24. 2.25. 2.26. 2.27. 2.28. Lista de factoriales . . . . . . . . . . Iteracin hastaque . . . . . . . . . . Composicin de funciones . . . . . . Intercambio de orden de argumentos Relacin de divisibilidad . . . . . . . Lista de divisores de un nmero . . Comprobacin de nmero primo . . Lista de primos . . . . . . . . . . . . Clculo del da de la semana . . . . . Diferenciacin numrica . . . . . . . Clculo de la raz cuadrada . . . . . Clculo de ceros de una funcin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

ndice general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 33 33 34 34 35 35 36 36 37 38 39 41 43 43 44 45 45 45 47 48 48 49 50 50 51 52 53 54 56 57 58 59 61 62 64 64 65 65 66

3. Estructuras de datos 3.1. Relacin de igualdad entre listas . . . . . . . . . . . . . . . . 3.2. Concatenacin de listas . . . . . . . . . . . . . . . . . . . . . . 3.3. Concatenacin de una lista de listas . . . . . . . . . . . . . . 3.4. Cabeza de una lista . . . . . . . . . . . . . . . . . . . . . . . . 3.5. Resto de una lista . . . . . . . . . . . . . . . . . . . . . . . . . 3.6. ltimo elemento . . . . . . . . . . . . . . . . . . . . . . . . . . 3.7. Lista sin el ltimo elemento . . . . . . . . . . . . . . . . . . . 3.8. Segmento inicial . . . . . . . . . . . . . . . . . . . . . . . . . . 3.9. Segmento inicial ltrado . . . . . . . . . . . . . . . . . . . . . 3.10. Segmento nal . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.11. Segmento nal ltrado . . . . . . . . . . . . . . . . . . . . . . 3.12. Nsimo elemento de una lista . . . . . . . . . . . . . . . . . 3.13. Inversa de una lista . . . . . . . . . . . . . . . . . . . . . . . . 3.14. Longitud de una lista . . . . . . . . . . . . . . . . . . . . . . . 3.15. Comprobacin de pertenencia de un elemento a una lista . . 3.16. Comprobacin de no pertenencia de un elemento a una lista 3.17. Comprobacin de que una lista est ordenada . . . . . . . . 3.18. Comprobacin de la igualdad de conjuntos . . . . . . . . . . 3.19. Insercin ordenada de un elemento en una lista . . . . . . . . 3.20. Ordenacin por insercin . . . . . . . . . . . . . . . . . . . . 3.21. Mnimo elemento de una lista . . . . . . . . . . . . . . . . . . 3.22. Mezcla de dos listas ordenadas . . . . . . . . . . . . . . . . . 3.23. Ordenacin por mezcla . . . . . . . . . . . . . . . . . . . . . . 3.24. Dgito correspondiente a un carcter numrico . . . . . . . . 3.25. Carcter correspondiente a un dgito . . . . . . . . . . . . . . 3.26. Lista innita de nmeros . . . . . . . . . . . . . . . . . . . . . 3.27. Lista con un elemento repetido . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

ndice general 3.28. 3.29. 3.30. 3.31. 3.32. 3.33. 3.34. 3.35. 3.36. 3.37. 3.38. 3.39. 3.40. 3.41. 3.42. 3.43. 3.44. 3.45. 3.46. 3.47. 3.48. 3.49. 3.50. 3.51. 3.52. 3.53. 3.54. Lista con un elemento repetido un nmero dado de veces Iteracin de una funcin . . . . . . . . . . . . . . . . . . . Conversin de nmero entero a cadena . . . . . . . . . . Clculo de primos mediante la criba de Erasttenes . . . Comprobacin de que todos los elementos son pares . . . Comprobacin de que todos los elementos son impares . Tringulos numricos . . . . . . . . . . . . . . . . . . . . . Posicin de un elemento en una lista . . . . . . . . . . . . Ordenacin rpida . . . . . . . . . . . . . . . . . . . . . . Primera componente de un par . . . . . . . . . . . . . . . Segunda componente de un par . . . . . . . . . . . . . . . Componentes de una terna . . . . . . . . . . . . . . . . . Creacin de variables a partir de pares . . . . . . . . . . . Divisin de una lista . . . . . . . . . . . . . . . . . . . . . Sucesin de Fibonacci . . . . . . . . . . . . . . . . . . . . . Incremento con el mnimo . . . . . . . . . . . . . . . . . . Longitud de camino entre puntos bidimensionales . . . . Nmeros racionales . . . . . . . . . . . . . . . . . . . . . . Mximo comn divisor . . . . . . . . . . . . . . . . . . . . Bsqueda en una lista de asociacin . . . . . . . . . . . . Emparejamiento de dos listas . . . . . . . . . . . . . . . . Emparejamiento funcional de dos listas . . . . . . . . . . Curricacin . . . . . . . . . . . . . . . . . . . . . . . . . . Funciones sobre rboles . . . . . . . . . . . . . . . . . . . Bsqueda en lista ordenada . . . . . . . . . . . . . . . . . Movimiento segn las direcciones . . . . . . . . . . . . . Los racionales como tipo abstracto de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5 67 68 68 69 70 71 72 73 74 74 75 76 76 77 77 79 80 81 83 84 85 86 86 87 90 91 91 95 95 96 97 97 97 98 99 101 102 103 104

4. Aplicaciones de programacin funcional 4.1. Segmentos iniciales . . . . . . . . . . . . . . 4.2. Segmentos nales . . . . . . . . . . . . . . . 4.3. Segmentos . . . . . . . . . . . . . . . . . . . 4.4. Sublistas . . . . . . . . . . . . . . . . . . . . 4.5. Comprobacin de subconjunto . . . . . . . 4.6. Comprobacin de la igualdad de conjuntos 4.7. Permutaciones . . . . . . . . . . . . . . . . . 4.8. Combinaciones . . . . . . . . . . . . . . . . 4.9. El problema de las reinas . . . . . . . . . . . 4.10. Nmeros de Hamming . . . . . . . . . . . . Bibliografa

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

6 Indice de deniciones

ndice general 105

Captulo 1 Introduccin a la programacin funcional


Contenido
1.1. Factorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. Nmero de combinaciones . . . . . . . . . . . . . . . . . . . . . . . . . . 7 9

1.3. Comprobacin de nmero impar . . . . . . . . . . . . . . . . . . . . . . . 10 1.4. Cuadrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5. Suma de cuadrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.6. Raices de ecuaciones de segundo grado . . . . . . . . . . . . . . . . . . . 13 1.7. Valor absoluto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.8. Signo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.9. Conjuncin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.10. Anterior de un nmero natural . . . . . . . . . . . . . . . . . . . . . . . . 15 1.11. Potencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.12. Funcin identidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

1.1.

Factorial

Ejercicio 1.1. Denir la funcin factorial tal que factorial n es el factorial de n. Por ejemplo,

factorial 4 ;24
Solucin: Vamos a presentar distintas deniciones. 7

Captulo 1. Introduccin a la programacin funcional 1. Primera denicin: Con condicionales:

fact1 :: Integer -> Integer fact1 n = if n == 0 then 1 else n * fact1 (n-1)


2. Segunda denicin: Mediante guardas:

fact2 fact2 | |

:: Integer -> Integer n n == 0 = 1 otherwise = n * fact2 (n-1)

3. Tercera denicin: Mediante patrones:

fact3 :: Integer -> Integer fact3 0 = 1 fact3 n = n * fact3 (n-1)


4. Cuarta denicin: Restriccin del dominio mediante guardas

fact4 fact4 | |

:: Integer -> Integer n n == 0 = 1 n >= 1 = n * fact4 (n-1)

5. Quinta denicin: Restriccin del dominio mediante patrones:

fact5 :: Integer -> Integer fact5 0 = 1 fact5 (n+1) = (n+1) * fact5 n


6. Sexta denicin: Mediante predenidas

fact6 :: Integer -> Integer fact6 n = product [1..n]


7. Sptima denicin: Mediante plegado:

fact7 :: Integer -> Integer fact7 n = foldr (*) 1 [1..n]

1.2. Nmero de combinaciones Se pueden comprobar todas las deniciones con

Factorial> [f 4 | f <- [fact1,fact2,fact3,fact4,fact5,fact6,fact7]] [24,24,24,24,24,24,24]


Las deniciones son equivalentes sobre los nmeros naturales:

prop_equivalencia :: Integer -> Property prop_equivalencia x = x >= 0 ==> (fact2 x == fact1 x && fact3 x == fact1 x && fact4 x == fact1 x && fact5 x == fact1 x && fact6 x == fact1 x && fact7 x == fact1 x)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


La denicin ms elegante es la quinta y es a la que nos referimos como factorial

factorial = fact5

1.2.

Nmero de combinaciones

Ejercicio 1.2. Denir la funcin comb tal que comb n k es el nmero de combinaciones de n elementos tomados de k en k; es decir, n m Por ejemplo.

n! k! (n k)!

comb 6 2 ; 15
Solucin:

comb n k = (factorial n) `div` ((factorial k) * (factorial (n-k)))

10

Captulo 1. Introduccin a la programacin funcional

1.3.

Comprobacin de nmero impar

Ejercicio 1.3. Denir la funcin impar tal que impar x se verica si el nmero x es impar. Por ejemplo,

impar 7 impar 6

; ;

True False

Solucin: Presentamos distintas deniciones: 1. Usando la predenida odd

impar1 :: Integer -> Bool impar1 = odd


2. Usando las predenidas not y even:

impar2 :: Integer -> Bool impar2 x = not (even x)


3. Usando las predenidas not, even y (.):

impar3 :: Integer -> Bool impar3 = not . even


4. Por recursin:

impar4 :: Integer -> Bool impar4 x | x > 0 = impar4_aux | otherwise = impar4_aux where impar4_aux 0 = impar4_aux 1 = impar4_aux (n+2) =
Las deniciones son equivalentes:

x (-x) False True impar4_aux n

prop_equivalencia :: Integer -> Bool prop_equivalencia x = impar2 x == impar1 x && impar3 x == impar1 x && impar4 x == impar1 x
Comprobacin

1.4. Cuadrado

11

Main> quickCheck prop_equivalencia OK, passed 100 tests.

1.4.

Cuadrado

Ejercicio 1.4. Denir la funcin cuadrado tal que cuadrado x es el cuadrado del nmero x. Por ejemplo,

cuadrado 3 ;

Solucin: Presentamos distintas deniciones: 1. Mediante (*)

cuadrado_1 :: Num a => a -> a cuadrado_1 x = x*x


2. Mediante (^)

cuadrado_2 :: Num a => a -> a cuadrado_2 x = x^2


3. Mediante secciones:

cuadrado_3 :: Num a => a -> a cuadrado_3 = (^2)


4. Usaremos como cuadrado la primera

cuadrado = cuadrado_1
Las deniciones son equivalentes:

prop_equivalencia :: Int -> Bool prop_equivalencia x = cuadrado_2 x == cuadrado_1 x && cuadrado_3 x == cuadrado_1 x
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

12

Captulo 1. Introduccin a la programacin funcional

1.5.

Suma de cuadrados

Ejercicio 1.5. Denir la funcin suma_de_cuadrados tal que suma_de_cuadrados l es la suma de los cuadrados de los elementos de la lista l. Por ejemplo,

suma_de_cuadrados [1,2,3] ;

14

Solucin: Presentamos distintas deniciones: 1. Con sum, map y cuadrado:

suma_de_cuadrados_1 :: [Integer] -> Integer suma_de_cuadrados_1 l = sum (map cuadrado l)


2. Con sum y listas intnsionales:

suma_de_cuadrados_2 :: [Integer] -> Integer suma_de_cuadrados_2 l = sum [x*x | x <- l]


3. Con sum, map y lambda:

suma_de_cuadrados_3 :: [Integer] -> Integer suma_de_cuadrados_3 l = sum (map (\x -> x*x) l)
4. Por recursin:

suma_de_cuadrados_4 :: [Integer] -> Integer suma_de_cuadrados_4 [] = 0 suma_de_cuadrados_4 (x:xs) = x*x + suma_de_cuadrados_4 xs


Las deniciones son equivalentes:

prop_equivalencia :: [Integer] -> Bool prop_equivalencia xs = suma_de_cuadrados_2 xs == suma_de_cuadrados_1 xs && suma_de_cuadrados_3 xs == suma_de_cuadrados_1 xs && suma_de_cuadrados_4 xs == suma_de_cuadrados_1 xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

1.6. Raices de ecuaciones de segundo grado

13

1.6.

Raices de ecuaciones de segundo grado

Ejercicio 1.6. Denir la funcin raices tal que raices a b c es la lista de las raices de la ecuacin ax2 + bc + c = 0. Por ejemplo,

raices 1 3 2

[-1.0,-2.0]

Solucin: Presentamos distintas deniciones: 1. Denicin directa:

raices_1 :: Double -> Double -> Double -> [Double] raices_1 a b c = [ (-b+sqrt(b*b-4*a*c))/(2*a), (-b-sqrt(b*b-4*a*c))/(2*a) ]
2. Con entornos locales

raices_2 :: Double -> Double -> Double -> [Double] raices_2 a b c = [(-b+d)/n, (-b-d)/n] where d = sqrt(b*b-4*a*c) n = 2*a
La segunda es mejor en legibilidad y en eciencia:

Main> :set +s Main> raices_1 1 [-1.0,-2.0] (134 reductions, Main> raices_2 1 [-1.0,-2.0] (104 reductions,

3 2 242 cells) 3 2 183 cells)

1.7.

Valor absoluto

Ejercicio 1.7. Redenir la funcin abs tal que abs x es el valor absoluto de x. Por ejemplo,

abs (-3) ; 3 abs 3 ; 3


Solucin: Presentamos distintas deniciones: 1. Con condicionales:

14

Captulo 1. Introduccin a la programacin funcional

n_abs_1 :: (Num a, Ord a) => a -> a n_abs_1 x = if x>0 then x else (-x)
2. Con guardas:

n_abs_2 :: (Num a, Ord a) => a -> a n_abs_2 x | x>0 = x | otherwise = -x


Las deniciones son equivalentes

prop_equivalencia :: Int -> Bool prop_equivalencia x = n_abs_1 x == abs x && n_abs_2 x == abs x

1.8.

Signo

Ejercicio 1.8. Redenir la funcin signum tal que signum x es -1 si x es negativo, 0 si x es cero y 1 si x es positivo. Por ejemplo,

signum 7 ; 1 signum 0 ; 0 signum (-4) ; -1


Solucin:

n_signum x | x > 0 = 1 | x == 0 = 0 | otherwise = -1


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Bool prop_equivalencia x = n_signum x == signum x


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

1.9. Conjuncin

15

1.9.

Conjuncin

Ejercicio 1.9. Redenir la funcin && tal que x && y es la conjuncin de x e y Por ejemplo,

True && False ; False


Solucin:

(&&&) :: Bool -> Bool -> Bool False &&& x = False True &&& x = x
Las deniciones son equivalentes:

prop_equivalencia x y = (x &&& y) == (x && y)


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

1.10.

Anterior de un nmero natural

Ejercicio 1.10. Denir la funcin anterior tal que anterior x es el anterior del nmero natural x. Por ejemplo,

anterior 3 ; 2 anterior 0 ; Program error: pattern match failure: anterior 0


Solucin: Presentamos distintas deniciones: 1. Con patrones:

anterior_1 :: Int -> Int anterior_1 (n+1) = n


2. Con guardas:

anterior_2 :: Int -> Int anterior_2 n | n>0 = n-1


Las deniciones son equivalentes sobre los nmeros naturales:

16

Captulo 1. Introduccin a la programacin funcional

prop_equivalencia :: Int -> Property prop_equivalencia n = n>0 ==> anterior_1 n == anterior_2 n


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

1.11.

Potencia

Ejercicio 1.11. Redenir la funcin potencia tal que potencia x y es x y . Por ejemplo,

potencia 2 4 ; 16 potencia 3.1 2 ; 9.61


Solucin: Presentamos distintas deniciones: 1. Por patrones:

potencia_1 :: Num a => a -> Int -> a potencia_1 x 0 = 1 potencia_1 x (n+1) = x * (potencia_1 x n)
2. Por condicionales:

potencia_2 :: Num a => a -> Int -> a potencia_2 x n = if n==0 then 1 else x * potencia_2 x (n-1)
3. Denicin eciente:

potencia_3 :: Num a => a -> Int -> a potencia_3 x 0 = 1 potencia_3 x n | n > 0 = f x (n-1) x where f _ 0 y = y f x n y = g x n where g x n | even n = g (x*x) (n`quot`2) | otherwise = f x (n-1) (x*y)
Las deniciones son equivalentes:

1.12. Funcin identidad

17

prop_equivalencia prop_equivalencia n >= 0 ==> (potencia_1 x potencia_2 x potencia_3 x


Comprobacin

:: Int -> Int -> Property x n = n == x^n && n == x^n && n == x^n)

Main> quickCheck prop_equivalencia OK, passed 100 tests.

1.12.

Funcin identidad

Ejercicio 1.12. Redenir la funcin id tal que id x es x. Por ejemplo,

id 3 ; 3
Solucin: La denicin es

n_id :: a -> a n_id x = x

18

Captulo 1. Introduccin a la programacin funcional

Captulo 2 Nmeros y funciones


Contenido
2.1. Casi igual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.2. Siguiente de un nmero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.3. Doble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.4. Mitad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.5. Inverso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.6. Potencia de dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.7. Reconocimiento de nmeros positivos . . . . . . . . . . . . . . . . . . . 24 2.8. Aplicacin de una funcin a los elementos de una lista . . . . . . . . . 25 2.9. Filtrado mediante una propiedad . . . . . . . . . . . . . . . . . . . . . . 26 2.10. Suma de los elementos de una lista . . . . . . . . . . . . . . . . . . . . . 27 2.11. Producto de los elementos de una lista . . . . . . . . . . . . . . . . . . . 27 2.12. Conjuncin sobre una lista . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.13. Disyuncin sobre una lista . . . . . . . . . . . . . . . . . . . . . . . . . . 29 2.14. Plegado por la derecha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.15. Plegado por la izquierda . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.16. Resultados acumulados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.17. Lista de factoriales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.18. Iteracin hastaque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.19. Composicin de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.20. Intercambio de orden de argumentos . . . . . . . . . . . . . . . . . . . . 34 2.21. Relacin de divisibilidad . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.22. Lista de divisores de un nmero . . . . . . . . . . . . . . . . . . . . . . . 35

19

20

Captulo 2. Nmeros y funciones


2.23. Comprobacin de nmero primo . . . . . . . . . . . . . . . . . . . . . . 35 2.24. Lista de primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.25. Clculo del da de la semana . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.26. Diferenciacin numrica . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.27. Clculo de la raz cuadrada . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.28. Clculo de ceros de una funcin . . . . . . . . . . . . . . . . . . . . . . . 39

2.1.

Casi igual

Ejercicio 2.1. Denir el operador ~= tal que x ~= y se verica si | x y| < 0,0001. Por ejemplo,

3.00001 ~= 3.00002 ; True 3.1 ~= 3.2 ; False


Solucin:

infix 4 ~= (~=) :: Float -> Float -> Bool x ~= y = abs(x-y) < 0.0001

2.2.

Siguiente de un nmero

Ejercicio 2.2. Denir la funcin siguiente tal que siguiente x sea el siguiente del nmero entero x. Por ejemplo,

siguiente 3 ; 4
Solucin: Presentamos distintas deniciones: 1. Mediante seccin:

siguiente_1 :: Integer -> Integer siguiente_1 = (+1)


2. Mediante instanciacin parcial:

siguiente_2 :: Integer -> Integer siguiente_2 = (+) 1


3. Usaremos como siguiente la primera

2.3. Doble

21

siguiente = siguiente_1
Las deniciones son equivalentes:

prop_equivalencia :: Integer -> Bool prop_equivalencia x = siguiente_1 x == siguiente_2 x


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.3.

Doble

Ejercicio 2.3. Denir la funcin doble tal que doble x es el doble de x. Por ejemplo,

doble 3 ; 6
Solucin: Se presentan distintas deniciones: 1. Denicin ecuacional:

doble_1 :: Num a => a -> a doble_1 x = 2*x


2. Denicin con instanciacin parcial:

doble_2 :: Num a => a -> a doble_2 = ((*) 2)


3. Denicin con secciones:

doble_3 :: Num a => a -> a doble_3 = (2*)


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Bool prop_equivalencia x = doble_2 x == doble_1 x && doble_3 x == doble_1 x

22 Comprobacin

Captulo 2. Nmeros y funciones

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.4.

Mitad

Ejercicio 2.4. Denir la funcin mitad tal que mitad x es la mitad de x. Por ejemplo,

mitad 6 ; 3.0 mitad 5 ; 2.5


Solucin: Se presentan distintas deniciones: 1. Denicin ecuacional:

mitad_1 :: Double -> Double mitad_1 x = x/2


2. Denicin con instanciacin parcial:

mitad_2 :: Double -> Double mitad_2 = (flip (/) 2)


3. Denicin con secciones:

mitad_3 :: Double -> Double mitad_3 = (/2)


Las deniciones son equivalentes para lon nmeros no nulos:

prop_equivalencia :: Double -> Bool prop_equivalencia x = mitad_2 x == mitad_1 x && mitad_3 x == mitad_1 x
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.5. Inverso

23

2.5.

Inverso

Ejercicio 2.5. Denir la funcin inverso tal que inverso x es el inverso de x. Por ejemplo,

inverso 2 ; 0.5
Solucin: Se presentan distintas deniciones: 1. Denicin ecuacional:

inverso_1 :: Double -> Double inverso_1 x = 1/x


2. Denicin con instanciacin parcial:

inverso_2 :: Double -> Double inverso_2 = ((/) 1)


3. Denicin con secciones:

inverso_3 :: Double -> Double inverso_3 = (1/)


Las deniciones son equivalentes para lon nmeros no nulos:

prop_equivalencia :: Double -> Property prop_equivalencia x = x /= 0 ==> (inverso_2 x == inverso_1 x && inverso_3 x == inverso_1 x)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.6.

Potencia de dos

Ejercicio 2.6. Denir la funcin dosElevadoA tal que dosElevadoA x es 2x . Por ejemplo,

dosElevadoA 3 ; 8
Solucin: Se presentan distintas deniciones:

24 1. Denicin ecuacional:

Captulo 2. Nmeros y funciones

dosElevadoA_1 :: Int -> Int dosElevadoA_1 x = 2^x


2. Denicin con instanciacin parcial:

dosElevadoA_2 :: Int -> Int dosElevadoA_2 = ((^) 2)


3. Denicin con secciones:

dosElevadoA_3 :: Int -> Int dosElevadoA_3 = (2^)


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Property prop_equivalencia x = x >= 0 ==> (dosElevadoA_2 x == dosElevadoA_1 x && dosElevadoA_3 x == dosElevadoA_1 x)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.7.

Reconocimiento de nmeros positivos

Ejercicio 2.7. Denir la funcin esPositivo tal que esPositivo se verica si x es positivo. Por ejemplo,

esPositivo 3 ; True esPositivo (-3) ; False


Solucin: Se presentan distintas deniciones: 1. Denicin ecuacional:

esPositivo_1 :: Int -> Bool esPositivo_1 x = x>0

2.8. Aplicacin de una funcin a los elementos de una lista 2. Denicin con instanciacin parcial:

25

esPositivo_2 :: Int -> Bool esPositivo_2 = (flip (>) 0)


3. Denicin con secciones:

esPositivo_3 :: Int -> Bool esPositivo_3 = (>0)


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Bool prop_equivalencia x = esPositivo_2 x == esPositivo_1 x && esPositivo_3 x == esPositivo_1 x
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.8.

Aplicacin de una funcin a los elementos de una lista

Ejercicio 2.8. Redenir la funcin map tal que map f l es la lista obtenida aplicando f a cada elemento de l. Por ejemplo,

map (2*) [1,2,3] ; [2,4,6]


Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

n_map_1 :: (a -> b) -> [a] -> [b] n_map_1 f [] = [] n_map_1 f (x:xs) = f x : n_map_1 f xs
2. Con listas intensionales:

n_map_2 :: (a -> b) -> [a] -> [b] n_map_2 f xs = [ f x | x <- xs ]

26 Las deniciones son equivalentes:

Captulo 2. Nmeros y funciones

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = n_map_1 (*2) xs == map (*2) xs && n_map_2 (*2) xs == map (*2) xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.9.

Filtrado mediante una propiedad

Ejercicio 2.9. Redenir la funcin filter tal que filter p l es la lista de los elementos de l que cumplen la propiedad p. Por ejemplo,

filter even [1,3,5,4,2,6,1] ; [4,2,6] filter (>3) [1,3,5,4,2,6,1] ; [5,4,6]


Solucin: Presentamos distintas deniciones: 1. Denicin por recursin:

n_filter_1 :: (a -> Bool) -> [a] -> [a] n_filter_1 p [] = [] n_filter_1 p (x:xs) | p x = x : n_filter_1 p xs | otherwise = n_filter_1 p xs
2. Denicin con listas intensionales:

n_filter_2 :: (a -> Bool) -> [a] -> [a] n_filter_2 p xs = [ x | x <- xs, p x ]
Las deniciones son equivalentes cuando la propiedad es even:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = n_filter_1 even xs == filter even xs && n_filter_2 even xs == filter even xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.10. Suma de los elementos de una lista

27

2.10.

Suma de los elementos de una lista

Ejercicio 2.10. Redenir la funcin sum tal que sum l es la suma de los elementos de l. Por ejemplo,

n_sum [1,3,6] ; 10
Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

n_sum_1 :: Num a => [a] -> a n_sum_1 [] = 0 n_sum_1 (x:xs) = x + n_sum_1 xs


2. Denicin con plegado:

n_sum_2 :: Num a => [a] -> a n_sum_2 = foldr (+) 0


Las deniciones son equivalentes:

prop_equivalencia prop_equivalencia n_sum_1 xs == n_sum_2 xs ==


Comprobacin

:: [Int] -> Bool xs = sum xs && sum xs

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.11.

Producto de los elementos de una lista

Ejercicio 2.11. Redenir la funcin product tal que product l es el producto de los elementos de l. Por ejemplo,

product [2,3,5] ; 30
Solucin: Presentamos distintas deniciones: 1. Denicin recursiva

28

Captulo 2. Nmeros y funciones

n_product_1 :: Num a => [a] -> a n_product_1 [] = 1 n_product_1 (x:xs) = x * n_product_1 xs


2. Denicin con plegado:

n_product_2 :: Num a => [a] -> a n_product_2 = foldr (*) 1


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = n_product_1 xs == product xs && n_product_2 xs == product xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.12.

Conjuncin sobre una lista

Ejercicio 2.12. Redenir la funcin and tal que and l se verica si todos los elementos de l son verdaderos. Por ejemplo,

and [1<2, 2<3, 1 /= 0] ; True and [1<2, 2<3, 1 == 0] ; False


Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

n_and_1 :: [Bool] -> Bool n_and_1 [] = True n_and_1 (x:xs) = x && n_and_1 xs
2. Denicin con plegado:

n_and_2 :: [Bool] -> Bool n_and_2 = foldr (&&) True

2.13. Disyuncin sobre una lista 3. Las deniciones son equivalentes:

29

prop_equivalencia prop_equivalencia n_and_1 xs == n_and_2 xs ==

:: [Bool] -> Bool xs = and xs && and xs

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.13.

Disyuncin sobre una lista

Ejercicio 2.13. Redenir la funcin or tal que or l se verica si algn elemento de l es verdadero. Por ejemplo,

or [1<2, 2<3, 1 /= 0] ; True or [3<2, 4<3, 1 == 0] ; False


Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

n_or_1 :: [Bool] -> Bool n_or_1 [] = False n_or_1 (x:xs) = x || n_or_1 xs


2. Denicin con plegado:

n_or_2 :: [Bool] -> Bool n_or_2 = foldr (||) False


3. Las deniciones son equivalentes:

prop_equivalencia :: [Bool] -> Bool prop_equivalencia xs = n_or_1 xs == or xs && n_or_2 xs == or xs Main> quickCheck prop_equivalencia OK, passed 100 tests.

30

Captulo 2. Nmeros y funciones

2.14.

Plegado por la derecha

Ejercicio 2.14. Redenir la funcin foldr tal que foldr op e l pliega por la derecha la lista l colocando el operador op entre sus elementos y el elemento e al nal. Es decir,

foldr op e [x1,x2,x3] ; x1 op (x2 op (x3 op e)) foldr op e [x1,x2,...,xn] ; x1 op (x2 op (... op (xn op e)))
Por ejemplo,

foldr (+) 3 [2,3,5] ; 13 foldr (-) 3 [2,3,5] ; 1


Solucin:

n_foldr :: (a -> b -> b) -> b -> [a] -> b n_foldr f e [] = e n_foldr f e (x:xs) = f x (n_foldr f e xs)

2.15.

Plegado por la izquierda

Ejercicio 2.15. Redenir la funcin foldl tal que foldl op e l pliega por la izquierda la lista l colocando el operador op entre sus elementos y el elemento e al principio. Es decir,

foldl op e [x1,x2,x3] ; (((e op x1) op x2) op x3 foldl op e [x1,x2,...,xn] ; (...((e op x1) op x2) ... op xn
Por ejemplo,

foldl (+) 3 [2,3,5] ; 13 foldl (-) 3 [2,3,5] ; -7


Solucin: Denicin recursiva

n_foldl :: (a -> b -> a) -> a -> [b] -> a n_foldl f z [] = z n_foldl f z (x:xs) = n_foldl f (f z x) xs
Las deniciones son equivalentes:

prop_equivalencia :: Int -> [Int] -> Bool prop_equivalencia n xs = n_foldl (+) n xs == foldl (+) n xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.16. Resultados acumulados

31

2.16.

Resultados acumulados

Ejercicio 2.16. Redenir la funcin scanr tal que scanr op e l pliega por la derecha la lista l colocando el operador op entre sus elementos y el elemento e al nal y escribe los resultados acumulados. Es decir,

scanr op e [x1,x2,x3] ; [x1 op (x2 op (x3 op e)), x2 op (x3 op e), x3 op e, e]


Por ejemplo,

scanr (+) 3 [2,3,5] ;[13,11,8,3]


Solucin:

n_scanr :: (a -> b -> b) -> b -> [a] -> [b] n_scanr f q0 [] = [q0] n_scanr f q0 (x:xs) = f x q : qs where qs@(q:_) = n_scanr f q0 xs
Las deniciones son equivalentes:

prop_equivalencia :: Int -> [Int] -> Bool prop_equivalencia n xs = n_scanr (+) n xs == scanr (+) n xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

2.17.

Lista de factoriales

Ejercicio 2.17. Denir la funcin factoriales tal que factoriales n es la lista de los factoriales desde el factorial de 0 hasta el factorial de n. Por ejemplo,

factoriales 5 ; [1,1,2,6,24,120]
Solucin: Se presentan distintas deniciones: 1. Denicin recursiva

32

Captulo 2. Nmeros y funciones

factoriales_1 :: Integer -> [Integer] factoriales_1 n = reverse (aux n) where aux 0 = [1] aux (n+1) = (factorial (n+1)) : aux n
2. Denicin recursiva con acumuladores:

factoriales_2 :: Integer -> [Integer] factoriales_2 n = reverse (aux (n+1) 0 [1]) where aux n m (x:xs) = if n==m then xs else aux n (m+1) (((m+1)*x):x:xs)
3. Denicin con listas intensionales:

factoriales_3 :: Integer -> [Integer] factoriales_3 n = [factorial x | x <- [0..n]]


4. Denicin con map:

factoriales_4 :: Integer -> [Integer] factoriales_4 n = map factorial [0..n]


5. Denicin con scanl:

factoriales_5 :: Integer -> [Integer] factoriales_5 n = scanl (*) 1 [1..n]


Las deniciones son equivalentes:

prop_equivalencia :: Integer -> Property prop_equivalencia n = n >= 0 ==> (factoriales_5 n == factoriales_1 n && factoriales_2 n == factoriales_1 n && factoriales_3 n == factoriales_1 n && factoriales_4 n == factoriales_1 n && factoriales_5 n == factoriales_1 n)
Comprobacin

2.18. Iteracin hastaque

33

Main> quickCheck prop_equivalencia OK, passed 100 tests.


Se puede observar la eciencia relativa en la siguiente sesin

Main> :set +s Main> factoriales_1 100 [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,...] (171696 reductions, 322659 cells) Main> factoriales_2 100 [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,...] (2457 reductions, 13581 cells) Main> factoriales_3 100 [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,...] (169929 reductions, 319609 cells) Main> factoriales_4 100 [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,...] (169930 reductions, 319611 cells) Main> factoriales_5 100 [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,...] (2559 reductions, 12876 cells) Main>
Se observa que las ms ecientes son la 2 y la 5.

2.18.

Iteracin hastaque

Ejercicio 2.18. Redenir la funcin until tal que until p f x aplica la f a x el menor nmero posible de veces, hasta alcanzar un valor que satisface el predicado p. Por ejemplo,

until (>1000) (2*) 1 ; 1024


Solucin:

n_until :: (a -> Bool) -> (a -> a) -> a -> a n_until p f x = if p x then x else n_until p f (f x)

2.19.

Composicin de funciones

Ejercicio 2.19. Redenir la funcin (.) tal que f . g es la composicin de las funciones f y g; es decir, la funcin que aplica x en f(g(x)). Por ejemplo,

34

Captulo 2. Nmeros y funciones

(cuadrado . siguiente) 2 ; 9 (siguiente . cuadrado) 2 ; 5


Solucin:

compuesta :: (b -> c) -> (a -> b) -> (a -> c) (f `compuesta` g) x = f (g x)


Por ejemplo,

(cuadrado `compuesta` siguiente) 2 ; 9 (siguiente `compuesta` cuadrado) 2 ; 5

2.20.

Intercambio de orden de argumentos

Ejercicio 2.20. Redenir la funcin flip que intercambia el orden de sus argumentos. Por ejemplo,

flip (-) 5 2 ; -3 flip (/) 5 2 ; 0.4


Solucin:

flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x

2.21.

Relacin de divisibilidad

Ejercicio 2.21. Denir la funcin divisible tal que divisible x y se verica si x es divisible por y. Por ejemplo,

divisible 9 3 ; True divisible 9 2 ; False


Solucin:

divisible :: Int -> Int -> Bool divisible x y = x `rem` y == 0

2.22. Lista de divisores de un nmero

35

2.22.

Lista de divisores de un nmero

Ejercicio 2.22. Denir la funcin divisores tal que divisores x es la lista de los divisores de x. Por ejemplo,

divisores 12 ; [1,2,3,4,6,12]
Solucin: Se presentan distintas deniciones: 1. Mediante ltro:

divisores_1 :: Int -> [Int] divisores_1 x = filter (divisible x) [1..x]


2. Mediante comprensin:

divisores_2 :: Int -> [Int] divisores_2 x = [y | y <- [1..x], divisible x y]


3. Equivalencia de las deniciones:

prop_equivalencia_1_2 x = divisores_1 x == divisores_2 x


Compobacin:

Divisores> quickCheck prop_equivalencia_1_2 OK, passed 100 tests.


4. Usaremos como divisores la segunda

divisores = divisores_2

2.23.

Comprobacin de nmero primo

Ejercicio 2.23. Denir la funcin primo tal que primo x se verica si x es primo. Por ejemplo,

primo 5 ; True primo 6 ; False


Solucin:

primo :: Int -> Bool primo x = divisores x == [1,x]

36

Captulo 2. Nmeros y funciones

2.24.

Lista de primos

Ejercicio 2.24. Denir la funcin primos tal que primos x es la lista de los nmeros primos menores o iguales que x. Por ejemplo,

primos 40 ; [2,3,5,7,11,13,17,19,23,29,31,37]
Solucin: Se presentan distintas deniciones: 1. Mediante ltrado:

primos_1 :: Int -> [Int] primos_1 x = filter primo [1..x]


2. Mediante comprensin:

primos_2 :: Int -> [Int] primos_2 x = [y | y <- [1..x], primo y]

2.25.

Clculo del da de la semana

Ejercicio 2.25. Denir la funcin da tal que dia d m a es el da de la semana correspondiente al da d del mes m del ao a. Por ejemplo,

da 31 12 2007 ; "lunes"
Solucin:

da d m a = daSemana ((nmeroDeDas d m a) `mod` 7)


donde se usan las siguientes funciones auxiliares

nmeroDa d m a es el nmero de das trancurridos desde el 1 de enero del ao 0 hasta el da d del mes m del ao a. Por ejemplo, nmeroDeDas 31 12 2007 ; 733041 nmeroDeDas d m a = (a-1)*365 + nmeroDeBisiestos a + sum (take (m-1) (meses a)) + d

nmeroDeBisiestos a es el nmero de aos bisiestos antes del ao a.

2.26. Diferenciacin numrica

37

nmeroDeBisiestos a = length (filter bisiesto [1..a-1]) bisiesto a se verica si el ao a es bisiesto. La denicin de ao bisiesto es
un ao divisible por 4 es un ao bisiesto (por ejemplo 1972); excepcin: si es divisible por 100, entonces no es un ao bisiesto excepcin de la excepcin: si es divisible por 400, entonces es un ao bisiesto (por ejemplo 2000).

bisiesto a = divisible a 4 && (not(divisible a 100) || divisible a 400) meses a es la lista con el nmero de das del los meses del ao a. Por ejemplo, meses 2000 ; [31,29,31,30,31,30,31,31,30,31,30,31] meses a = [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] where feb | bisiesto a = 29 | otherwise = 28 daSemana n es el nsimo da de la semana comenzando con 0 el domingo. Por ejemplo, daSemana 2 ; "martes" daSemana daSemana daSemana daSemana daSemana daSemana daSemana 0 1 2 3 4 5 6 = = = = = = = "domingo" "lunes" "martes" "mircoles" "jueves" "viernes" "sbado"

2.26.

Diferenciacin numrica

Ejercicio 2.26. Denir la funcin derivada tal que derivada a f x es el valor de la derivada de la funcin f en el punto x con aproximacin a. Por ejemplo,

38

Captulo 2. Nmeros y funciones

derivada 0.001 sin pi ; -0.9999273 derivada 0.001 cos pi ; 0.0004768371


Solucin:

derivada :: Float -> (Float -> Float) -> Float -> Float derivada a f x = (f(x+a)-f(x))/a
Ejercicio 2.27. Denir las siguientes versiones de derivada:

derivadaBurda cuando la aproximacin es 0.01. derivadaFina cuando la aproximacin es 0.0001. derivadaSuper cuando la aproximacin es 0.000001.
Por ejemplo,

derivadaFina cos pi ; 0.0 derivadaFina sin pi ; -0.9989738


Solucin:

derivadaBurda = derivada 0.01 derivadaFina = derivada 0.0001 derivadaSuper = derivada 0.000001


Ejercicio 2.28. Denir la funcin derivadaFinaDelSeno tal que derivadaFinaDelSeno x es el valor de la derivada na del seno en x. Por ejemplo,

derivadaFinaDelSeno pi ; -0.9989738
Solucin:

derivadaFinaDelSeno = derivadaFina sin

2.27.

Clculo de la raz cuadrada

Ejercicio 2.29. Denir la funcin RaizCuadrada tal que raiz x es la raz cuadrada de x calculada usando la siguiente propiedad x Si y es una aproximacin de x, entonces 1 2 ( y + y ) es una aproximacin mejor. Por ejemplo,

2.28. Clculo de ceros de una funcin

39

raizCuadrada 9 ; 3.00000000139698
Solucin:

raizCuadrada :: Double -> Double raizCuadrada x = until aceptable mejorar 1 where mejorar y = 0.5*(y+x/y) aceptable y = abs(y*y-x) < 0.00001

2.28.

Clculo de ceros de una funcin

Ejercicio 2.30. Denir la funcin puntoCero tal que puntoCero f es un cero de la funcin f calculado usando la siguiente propiedad Si b es una aproximacin para el punto cero de f , entonces b aproximacin. Por ejemplo,
f (b) f (b)

es una mejor

puntoCero cos ; 1.570796


Solucin:

puntoCero f = until aceptable mejorar 1 where mejorar b = b - f b / derivadaFina f b aceptable b = abs (f b) < 0.00001
Ejercicio 2.31. Usando puntoCero, denir las siguientes funciones:

raz_cuadrada tal que raz_cuadrada x es la raz cuadrada de x. raz_cbica tal que raz_cbica x es la raz cbica de x. arco_seno tal que arco_seno x es el arco cuyo seno es x. arco_coseno tal que arco_coseno x es el arco cuyo coseno es x.
Solucin:

raz_cuadrada_1 a = puntoCero f where f x = x*x-a raz_cbica_1 a = puntoCero f where f x = x*x*x-a

40

Captulo 2. Nmeros y funciones

arco_seno_1 a = puntoCero f where f x = sin x - a arco_coseno_1 a = puntoCero f where f x = cos x - a


Ejercicio 2.32. Usando puntoCero, denir la funcin inversa tal que inversa f es la inversa de la funcin f. Solucin:

inversa g a = puntoCero f where f x = g x - a


Ejercicio 2.33. Usando la funcin inversa, redenir las funciones raz_cuadrada, raz_cbica, arco_seno y arco_coseno. Solucin:

raz_cuadrada_2 raz_cbica_2 arco_seno_2 arco_coseno_2

= = = =

inversa inversa inversa inversa

(^2) (^3) sin cos

Captulo 3 Estructuras de datos


Contenido
3.1. Relacin de igualdad entre listas . . . . . . . . . . . . . . . . . . . . . . . 43 3.2. Concatenacin de listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.3. Concatenacin de una lista de listas . . . . . . . . . . . . . . . . . . . . . 44 3.4. Cabeza de una lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.5. Resto de una lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.6. ltimo elemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.7. Lista sin el ltimo elemento . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.8. Segmento inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.9. Segmento inicial ltrado . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.10. Segmento nal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 3.11. Segmento nal ltrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.12. Nsimo elemento de una lista . . . . . . . . . . . . . . . . . . . . . . . . 50 3.13. Inversa de una lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.14. Longitud de una lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.15. Comprobacin de pertenencia de un elemento a una lista . . . . . . . . 53 3.16. Comprobacin de no pertenencia de un elemento a una lista . . . . . . 54 3.17. Comprobacin de que una lista est ordenada . . . . . . . . . . . . . . . 56 3.18. Comprobacin de la igualdad de conjuntos . . . . . . . . . . . . . . . . 57 3.19. Insercin ordenada de un elemento en una lista . . . . . . . . . . . . . . 58 3.20. Ordenacin por insercin . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.21. Mnimo elemento de una lista . . . . . . . . . . . . . . . . . . . . . . . . 61 3.22. Mezcla de dos listas ordenadas . . . . . . . . . . . . . . . . . . . . . . . . 62

41

42

Captulo 3. Estructuras de datos


3.23. Ordenacin por mezcla . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.24. Dgito correspondiente a un carcter numrico . . . . . . . . . . . . . . 64 3.25. Carcter correspondiente a un dgito . . . . . . . . . . . . . . . . . . . . 65 3.26. Lista innita de nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 3.27. Lista con un elemento repetido . . . . . . . . . . . . . . . . . . . . . . . . 66 3.28. Lista con un elemento repetido un nmero dado de veces . . . . . . . . 67 3.29. Iteracin de una funcin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 3.30. Conversin de nmero entero a cadena . . . . . . . . . . . . . . . . . . . 68 3.31. Clculo de primos mediante la criba de Erasttenes . . . . . . . . . . . 69 3.32. Comprobacin de que todos los elementos son pares . . . . . . . . . . . 70 3.33. Comprobacin de que todos los elementos son impares . . . . . . . . . 71 3.34. Tringulos numricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.35. Posicin de un elemento en una lista . . . . . . . . . . . . . . . . . . . . 73 3.36. Ordenacin rpida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 3.37. Primera componente de un par . . . . . . . . . . . . . . . . . . . . . . . . 74 3.38. Segunda componente de un par . . . . . . . . . . . . . . . . . . . . . . . 75 3.39. Componentes de una terna . . . . . . . . . . . . . . . . . . . . . . . . . . 76 3.40. Creacin de variables a partir de pares . . . . . . . . . . . . . . . . . . . 76 3.41. Divisin de una lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 3.42. Sucesin de Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 3.43. Incremento con el mnimo . . . . . . . . . . . . . . . . . . . . . . . . . . 79 3.44. Longitud de camino entre puntos bidimensionales . . . . . . . . . . . . 80 3.45. Nmeros racionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 3.46. Mximo comn divisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 3.47. Bsqueda en una lista de asociacin . . . . . . . . . . . . . . . . . . . . . 84 3.48. Emparejamiento de dos listas . . . . . . . . . . . . . . . . . . . . . . . . . 85 3.49. Emparejamiento funcional de dos listas . . . . . . . . . . . . . . . . . . 86 3.50. Curricacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 3.51. Funciones sobre rboles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 3.52. Bsqueda en lista ordenada . . . . . . . . . . . . . . . . . . . . . . . . . . 90 3.53. Movimiento segn las direcciones . . . . . . . . . . . . . . . . . . . . . . 91 3.54. Los racionales como tipo abstracto de datos . . . . . . . . . . . . . . . . 91

3.1. Relacin de igualdad entre listas

43

3.1.

Relacin de igualdad entre listas

Ejercicio 3.1. Denir la funcin igualLista tal que igualLista xs ys se verica si las dos listas xs e ys son iguales. Por ejemplo,

igualLista :: Eq a => [a] -> [a] -> Bool igualLista [1,2,3,4,5] [1..5] ; True igualLista [1,3,2,4,5] [1..5] ; False
Nota: igualLista es equivalente a ==. Solucin:

igualLista igualLista igualLista igualLista

:: Eq a => [a] -> [a] -> Bool [] [] = True (x:xs) (y:ys) = x==y && igualLista xs ys _ _ = False

Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> [Int] -> Bool prop_equivalencia xs ys = igualLista xs ys == (xs==ys)


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.2.

Concatenacin de listas

Ejercicio 3.2. Denir la funcin conc tal que conc l1 l2 es la concatenacin de l1 y l2. Por ejemplo,

conc [2,3] [3,2,4,1] ; [2,3,3,2,4,1]


Nota: conc es equivalente a (++). Solucin:

conc :: [a] -> [a] -> [a] conc [] ys = ys conc (x:xs) ys = x : (conc xs ys)

44 Las deniciones son equivalentes:

Captulo 3. Estructuras de datos

prop_equivalencia :: [Int] -> [Int] -> Bool prop_equivalencia xs ys = conc xs ys == xs++ys


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.3.

Concatenacin de una lista de listas

Ejercicio 3.3. Redenir la funcin concat tal que concat l es la concatenacin de las lista de l. Por ejemplo,

concat [[1,2,3],[4,5],[],[1,2]] ; [1,2,3,4,5,1,2]


Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

concat_1 :: [[a]] -> [a] concat_1 [] = [] concat_1 (xs:xss) = xs ++ concat_1 xss


2. Denin con plegados:

concat_2 :: [[a]] -> [a] concat_2 = foldr (++) []


3. Denin por comprensin:

concat_3 :: [[a]] -> [a] concat_3 xss = [x | xs <- xss, x <- xs]
Las deniciones son equivalentes:

prop_equivalencia prop_equivalencia concat_1 x == concat_2 x == concat_3 x ==

:: [[Int]] -> Bool x = concat x && concat x && concat x

3.4. Cabeza de una lista Comprobacin:

45

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.4.

Cabeza de una lista

Ejercicio 3.4. Redenir la funcin head tal que head l es la cabeza de la lista l. Por ejemplo,

head [3,5,2] ; 3 head [] ; Program error: pattern match failure: head []


Solucin:

n_head :: [a] -> a n_head (x:_) = x

3.5.

Resto de una lista

Ejercicio 3.5. Redenir la funcin tail tal que tail l es el resto de la lista l. Por ejemplo,

tail [3,5,2] ; [5,2] tail (tail [1]) ; Program error: pattern match failure: tail []
Solucin:

n_tail :: [a] -> [a] n_tail (_:xs) = xs

3.6.

ltimo elemento

Ejercicio 3.6. Redenir la funcin last tal que last l es el ltimo elemento de la lista l. Por ejemplo,

last [1,2,3] ; 3 last [] ; Program error: pattern match failure: last []


Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

46

Captulo 3. Estructuras de datos

n_last_1 :: [a] -> a n_last_1 [x] = x n_last_1 (_:xs) = n_last_1 xs


2. Con plegados:

n_last_2 :: [a] -> a n_last_2 = foldr1 (\x y -> y)


3. Con head y reverse:

n_last_3 :: [a] -> a n_last_3 xs = head (reverse xs)


4. Con head, reverse y (.):

n_last_4 :: [a] -> a n_last_4 = head . reverse


5. Con (!!) y length

n_last_5 :: [a] -> a n_last_5 xs = xs !! (length xs - 1)


Las deniciones son equivalentes para las listas no vaca:

prop_equivalencia :: [Int] -> Property prop_equivalencia xs = not (null xs) ==> (n_last_1 xs == last xs && n_last_2 xs == last xs && n_last_3 xs == last xs && n_last_4 xs == last xs && n_last_5 xs == last xs)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.7. Lista sin el ltimo elemento

47

3.7.

Lista sin el ltimo elemento

Ejercicio 3.7. Redenir la funcin init tal que init l es la lista l sin el ltimo elemento. Por ejemplo,

init [1,2,3] ; [1,2] init [4] ; []


Solucin: Presentamos distintas deniciones: 1. Denicin recursiva:

n_init_1 :: [a] -> [a] n_init_1 [x] = [] n_init_1 (x:xs) = x : n_init_1 xs


2. Denicin con tail y reverse:

n_init_2 :: [a] -> [a] n_init_2 xs = reverse (tail (reverse xs))


3. Denicin con tail, reverse y (.):

n_init_3 :: [a] -> [a] n_init_3 = reverse . tail . reverse


Las deniciones son equivalentes sobre listas no vaca:

prop_equivalencia :: [Int] -> Property prop_equivalencia xs = not (null xs) ==> (n_init_1 xs == init xs && n_init_2 xs == init xs && n_init_3 xs == init xs)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

48

Captulo 3. Estructuras de datos

3.8.

Segmento inicial

Ejercicio 3.8. Denir la funcin take tal que take n l es la lista de los n primeros elementos de l. Por ejemplo,

take 2 [3,5,4,7] ; [3,5] take 12 [3,5,4,7] ; [3,5,4,7]


Solucin:

n_take n_take n_take n_take

:: Int -> [a] n _ | n <= 0 _ [] n (x:xs)

-> = = =

[a] [] [] x : n_take (n-1) xs

Las deniciones son equivalentes:

prop_equivalencia :: Int -> [Int] -> Bool prop_equivalencia n xs = n_take n xs == take n xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.9.

Segmento inicial ltrado

Ejercicio 3.9. Redenir la funcin takeWhile tal que takeWhile p l es la lista de los elementos iniciales de l que verican el predicado p. Por ejemplo,

takeWhile even [2,4,6,7,8,9] ; [2,4,6]


Solucin: Denicin recursiva:

n_takeWhile :: (a -> Bool) -> [a] -> [a] n_takeWhile p [] = [] n_takeWhile p (x:xs) | p x = x : n_takeWhile p xs | otherwise = []
Las deniciones son equivalentes:

3.10. Segmento nal

49

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = n_takeWhile even xs == takeWhile even xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.10.

Segmento nal

Ejercicio 3.10. Redenir la funcin drop tal que drop n l es la lista obtenida eliminando los primeros n elementos de la lista l. Por ejemplo,

drop 2 [3..10] ; [5,6,7,8,9,10] drop 12 [3..10] ; []


Solucin:

n_drop n_drop n_drop n_drop

:: Int -> [a] n xs | n <= 0 _ [] n (_:xs)

-> [a] = xs = [] = n_drop (n-1) xs

Las deniciones son equivalentes:

prop_equivalencia :: Int -> [Int] -> Bool prop_equivalencia n xs = n_drop n xs == drop n xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


La relacin entre los segmentos iniciales y nales es

prop_take_y_drop :: Int -> [Int] -> Bool prop_take_y_drop n xs = n_take n xs ++ n_drop n xs == xs


Comprobacin

Main> quickCheck prop_take_y_drop OK, passed 100 tests.

50

Captulo 3. Estructuras de datos

3.11.

Segmento nal ltrado

Ejercicio 3.11. Redenir la funcin dropWhile tal que dropWhile p l es la lista l sin los elementos iniciales que verican el predicado p. Por ejemplo,

dropWhile even [2,4,6,7,8,9] ; [7,8,9]


Solucin:

n_dropWhile :: (a -> Bool) -> [a] -> [a] n_dropWhile p [] = [] n_dropWhile p l@(x:xs) | p x = n_dropWhile p xs | otherwise = l
Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = n_dropWhile even xs == dropWhile even xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.12.

Nsimo elemento de una lista

Ejercicio 3.12. Denir la funcin nth tal que nth l n es elemento nsimo de l, empezando a numerar con el 0. Por ejemplo,

nth [1,3,2,4,9,7] 3 ; 4
Nota: nth es equivalente a (!!). Solucin:

nth :: [a] -> Int -> a nth (x:_) 0 = x nth (_:xs) n = nth xs (n-1)
Las deniciones son equivalentes:

3.13. Inversa de una lista

51

prop_equivalencia :: [Int] -> Int -> Property prop_equivalencia xs n = 0 < n && n < length xs ==> nth xs n == xs!!n
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.13.

Inversa de una lista

Ejercicio 3.13. Redenir la funcin reverse tal que reverse l es la inversa de l. Por ejemplo,

reverse [1,4,2,5] ; [5,2,4,1]


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

n_reverse_1 :: [a] -> [a] n_reverse_1 [] = [] n_reverse_1 (x:xs) = n_reverse_1 xs ++ [x]


2. Denicin recursiva con acumulador:

n_reverse_2 :: [a] -> [a] n_reverse_2 xs = n_reverse_2_aux xs [] where n_reverse_2_aux [] ys = ys n_reverse_2_aux (x:xs) ys = n_reverse_2_aux xs (x:ys)
3. Con plegado:

n_reverse_3 :: [a] -> [a] n_reverse_3 = foldl (flip (:)) []


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> prop_equivalencia xs = n_reverse_1 xs == reverse n_reverse_2 xs == reverse n_reverse_3 xs == reverse

Bool xs && xs && xs

52 Comprobacin

Captulo 3. Estructuras de datos

Main> quickCheck prop_equivalencia OK, passed 100 tests.


Comparacin de eciencia : Nmero de reducciones al invertir la lista [1..n] n Def. 1 Def. 2 Def. 3 100 7.396 2.347 2.446 200 24.746 4.647 4.846 400 89.446 9.247 9.646 1000 523.546 23.047 24.046

3.14.

Longitud de una lista

Ejercicio 3.14. Redenir la funcin length tal que length l es el nmero de elementos de l. Por ejemplo,

length [1,3,6] ; 3
Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

n_length_1 :: [a] -> Int n_length_1 [] = 0 n_length_1 (_:xs) = 1 + n_length_1 xs


2. Denicin con plegado por la derecha:

n_length_2 :: [a] -> Int n_length_2 = foldr (\x y -> y+1) 0


3. Denicin con plegado por la izquierda:

n_length_3 :: [a] -> Int n_length_3 = foldl (\x y -> x+1) 0


4. Denicin con sum y listas intensionales:

n_length_4 :: [a] -> Int n_length_4 xs = sum [1 | x <- xs]

3.15. Comprobacin de pertenencia de un elemento a una lista Las deniciones son equivalentes:

53

prop_equivalencia prop_equivalencia n_length_1 xs n_length_2 xs n_length_3 xs n_length_4 xs


Comprobacin

:: xs == == == ==

[Int] -> Bool = length xs && length xs && length xs && length xs

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.15.

Comprobacin de pertenencia de un elemento a una lista

Ejercicio 3.15. Redenir la funcin elem tal que elem e l se verica si e es un elemento de l. Por ejemplo,

elem 2 [1,2,3] ; True elem 4 [1,2,3] ; False


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva

n_elem_1 :: Eq a => a -> [a] -> Bool n_elem_1 _ [] = False n_elem_1 x (y:ys) = (x==y) || n_elem_1 x ys
2. Denicin con plegado:

n_elem_2 :: Eq a => a -> [a] -> Bool n_elem_2 x = foldl (\z y -> z || x==y) False
3. Denicin con or y map

n_elem_3 :: Eq a => a -> [a] -> Bool n_elem_3 x ys = or (map (==x) ys)
4. Denicin con or, map y (.)

54

Captulo 3. Estructuras de datos

n_elem_4 :: Eq a => a -> [a] -> Bool n_elem_4 x = or . map (==x)


5. Denicin con or y lista intensional:

n_elem_5 :: Eq a => a -> [a] -> Bool n_elem_5 x ys = or [x==y | y <- ys]
6. Denicin con any y (.)

n_elem_6 :: Eq a => a -> [a] -> Bool n_elem_6 = any . (==)


7. Denicin con not y notElem

n_elem_7 :: Eq a => a -> [a] -> Bool n_elem_7 x = not . (notElem x)


Las deniciones son equivalentes:

prop_equivalencia prop_equivalencia n_elem_1 x ys n_elem_2 x ys n_elem_3 x ys n_elem_4 x ys n_elem_5 x ys n_elem_6 x ys n_elem_7 x ys


Comprobacin

:: Int -> x ys = == elem x == elem x == elem x == elem x == elem x == elem x == elem x

[Int] -> Bool ys ys ys ys ys ys ys && && && && && &&

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.16.

Comprobacin de no pertenencia de un elemento a una lista

Ejercicio 3.16. Redenir la funcin notElem tal que notElem e l se verica si e no es un elemento de l. Por ejemplo,

3.16. Comprobacin de no pertenencia de un elemento a una lista

55

notElem 2 [1,2,3] ; False notElem 4 [1,2,3] ; True


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva

n_notElem_1 :: Eq a => a -> [a] -> Bool n_notElem_1 _ [] = True n_notElem_1 x (y:ys) = (x/=y) && n_notElem_1 x ys
2. Denicin con plegado:

n_notElem_2 :: Eq a => a -> [a] -> Bool n_notElem_2 x = foldl (\z y -> z && x/=y) True
3. Denicin con or y map

n_notElem_3 :: Eq a => a -> [a] -> Bool n_notElem_3 x ys = and (map (/=x) ys)
4. Denicin con or, map y (.)

n_notElem_4 :: Eq a => a -> [a] -> Bool n_notElem_4 x = and . map (/=x)
5. Denicin con or y lista intensional:

n_notElem_5 :: Eq a => a -> [a] -> Bool n_notElem_5 x ys = and [x/=y | y <- ys]
6. Denicin con any y (.)

n_notElem_6 :: Eq a => a -> [a] -> Bool n_notElem_6 = all . (/=)


7. Denicin con not y elem

n_notElem_7 :: Eq a => a -> [a] -> Bool n_notElem_7 x = not . (elem x)


Las deniciones son equivalentes:

56

Captulo 3. Estructuras de datos

prop_equivalencia prop_equivalencia n_notElem_1 x n_notElem_2 x n_notElem_3 x n_notElem_4 x n_notElem_5 x n_notElem_6 x n_notElem_7 x


Comprobacin

:: Int -> [Int] x ys = ys == notElem x ys == notElem x ys == notElem x ys == notElem x ys == notElem x ys == notElem x ys == notElem x

-> Bool ys ys ys ys ys ys ys && && && && && &&

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.17.

Comprobacin de que una lista est ordenada

Ejercicio 3.17. Denir la funcin lista_ordenada tal que lista_ordenada l se verica si la lista l est ordenada de menor a mayor. Por ejemplo,

lista_ordenada [1,3,3,5] ; True lista_ordenada [1,3,5,3] ; False


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva

lista_ordenada_1 lista_ordenada_1 lista_ordenada_1 lista_ordenada_1

:: Ord a [] [_] (x:y:xs)

=> [a] -> Bool = True = True = (x <= y) && lista_ordenada_1 (y:xs)

2. Denicin con and, y zipWith

lista_ordenada_2 lista_ordenada_2 lista_ordenada_2 lista_ordenada_2

:: Ord a => [a] -> Bool [] = True [_] = True xs = and (zipWith (<=) xs (tail xs))

3. Usaremos como lista_ordenada la primera

3.18. Comprobacin de la igualdad de conjuntos

57

lista_ordenada :: Ord a => [a] -> Bool lista_ordenada = lista_ordenada_1


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = lista_ordenada_1 xs == lista_ordenada_2 xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.18.

Comprobacin de la igualdad de conjuntos

Ejercicio 3.18. Denir la funcin igual_conjunto tal que igual_conjunto l1 l2 se verica si las listas l1 y l2 vistas como conjuntos son iguales Por ejemplo,

igual_conjunto [1..10] [10,9..1] ; True igual_conjunto [1..10] [11,10..1] ; False


Solucin: Se presentan distintas deniciones: 1. Usando subconjunto

igual_conjunto_1 :: Eq a => [a] -> [a] -> Bool igual_conjunto_1 xs ys = subconjunto xs ys && subconjunto ys xs
2. Por recursin.

igual_conjunto_2 :: Eq a => [a] -> [a] -> Bool igual_conjunto_2 xs ys = aux (nub xs) (nub ys) where aux [] [] = True aux (x:_) [] = False aux [] (y:_) = False aux (x:xs) ys = x `elem` ys && aux xs (delete x ys)
3. Usando sort

igual_conjunto_3 :: (Eq a, Ord a) => [a] -> [a] -> Bool igual_conjunto_3 xs ys = sort (nub xs) == sort (nub ys)

58 4. Usaremos como igual_conjunto la primera

Captulo 3. Estructuras de datos

igual_conjunto :: Eq a => [a] -> [a] -> Bool igual_conjunto = igual_conjunto_1


Las deniciones son equivalentes:

prop_equivalencia :: prop_equivalencia xs igual_conjunto_2 igual_conjunto_3


Comprobacin

[Int] -> [Int] -> Bool ys = xs ys == igual_conjunto_1 xs ys && xs ys == igual_conjunto_1 xs ys

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.19.

Insercin ordenada de un elemento en una lista

Ejercicio 3.19. Denir la funcin inserta tal que inserta e l inserta el elemento e en la lista l delante del primer elemento de l mayor o igual que e. Por ejemplo,

inserta 5 [2,4,7,3,6,8,10] ; [2,4,5,7,3,6,8,10]


Solucin:

inserta :: Ord a inserta e [] inserta e (x:xs) | e<=x | otherwise

=> a -> [a] -> [a] = [e] = e:x:xs = x : inserta e xs

Se puede denir el generador de QuickCheck para que cree lista ordenadas y compruebe que inserta las mantiene ordenada

listaOrdenada :: Gen [Integer] listaOrdenada = do n <- arbitrary listaDesde n where listaDesde n = frequency [(1, return []),

3.20. Ordenacin por insercin

59

(5, do i <- arbitrary ns <- listaDesde (n+abs i) return (n:ns))] prop_inserta x = forAll listaOrdenada $ \xs -> collect (length xs) $ lista_ordenada (inserta x xs)
En efecto,

Inserta> quickCheck prop_inserta OK, passed 100 tests. 18% 2. 16% 1. 10% 5. 10% 0. 9% 6. 7% 7. 7% 3. 4% 9. 4% 12. 3% 4. 2% 8. 2% 19. 2% 13. 1% 22. 1% 18. 1% 17. 1% 15. 1% 11. 1% 10.

3.20.

Ordenacin por insercin

Ejercicio 3.20. Denir la funcin ordena_por_insercin tal que ordena_por_insercin l es la lista l ordenada mediante insercin, Por ejemplo,

ordena_por_insercin [2,4,3,6,3] ; [2,3,3,4,6]


Solucin: Se presentan distintas deniciones:

60 1. Denicin recursiva

Captulo 3. Estructuras de datos

ordena_por_insercin_1 :: Ord a => [a] -> [a] ordena_por_insercin_1 [] = [] ordena_por_insercin_1 (x:xs) = inserta x (ordena_por_insercin_1 xs)
2. Denicin por plegado por la derecha

ordena_por_insercin_2 :: Ord a => [a] -> [a] ordena_por_insercin_2 = foldr inserta []


3. Denicin por plegado por la izquierda

ordena_por_insercin_3 :: Ord a => [a] -> [a] ordena_por_insercin_3 = foldl (flip inserta) []
Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = ordena_por_insercin_2 xs == ordena_por_insercin_1 xs && ordena_por_insercin_2 xs == ordena_por_insercin_1 xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


Al comparar la eciencia

Main> :set +s Main> ordena_por_insercin_1 [100,99..1] ,,, (51959 reductions, 68132 cells) Main> ordena_por_insercin_2 [100,99..1] ,,, (51960 reductions, 68034 cells) Main> ordena_por_insercin_3 [100,99..1] ... (3451 reductions, 5172 cells)
se observa que la tercera denicin es ms eciente. En los sucesivo usaremos como ordena_por_insercin la tercera

3.21. Mnimo elemento de una lista

61

ordena_por_insercin :: Ord a => [a] -> [a] ordena_por_insercin = ordena_por_insercin_2


El valor de ordena_por_insercin es una lista ordenada

prop_ordena_por_insercin_ordenada :: [Int] -> Bool prop_ordena_por_insercin_ordenada xs = lista_ordenada (ordena_por_insercin xs) Ordena_por_insercion> quickCheck prop_ordena_por_insercin_ordenada OK, passed 100 tests.

3.21.

Mnimo elemento de una lista

Ejercicio 3.21. Redenir la funcin minimum tal que minimum l es el menor elemento de la lista l. Por ejemplo,

minimum [3,2,5] ; 2
Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

n_minimum_1 :: Ord a => [a] -> a n_minimum_1 [x] = x n_minimum_1 (x:y:xs) = n_minimum_1 ((min x y):xs)
2. Denicin con plegado:

n_minimum_2 :: Ord a => [a] -> a n_minimum_2 = foldl1 min


3. Denicin mediante ordenacin:

n_minimum_3 :: Ord a => [a] -> a n_minimum_3 = head . ordena_por_insercin


Las deniciones son equivalentes:

62

Captulo 3. Estructuras de datos

prop_equivalencia :: [Int] -> Property prop_equivalencia xs = not (null xs) ==> (n_minimum_1 xs == minimum xs && n_minimum_2 xs == minimum xs && n_minimum_3 xs == minimum xs )
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


La eciencia de las tres deniciones es equivalente:

Main :set +s Main> n_minimum_1 1 (2644 reductions, Main> n_minimum_2 1 (2548 reductions, Main> n_minimum_3 1 (2552 reductions, minimum_3 minimum_3 minimum_3 minimum_3

[100,99..1] 3568 cells) [100,99..1] 3373 cells) [100,99..1] 3477 cells) ( 300 ( 2550 ( 25050 (250050 reductions, 416 cells) reductions, 3476 cells) reductions, 34076 cells) reductions, 340077 cells) ( 750 ( 51960 ( 5019060 (500190060 reductions, 1028 reductions, 68034 reductions, 6530485 reductions, 650313987 cells) cells) cells) cells)

La complejidad de minimum_3 es lineal:

[10,9..1] [100,99..1] [1000,999..1] [10000,9999..1]

aunque la complejidad de ordena_por_insercin es cuadrtica

ordena_por_insercin ordena_por_insercin ordena_por_insercin ordena_por_insercin

[10,9..1] [100,99..1] [1000,999..1] [10000,9999..1]

3.22.

Mezcla de dos listas ordenadas

Ejercicio 3.22. Denir la funcin mezcla tal que mezcla l1 l2 es la lista ordenada obtenida al mezclar las listas ordenadas l1 y l2. Por ejemplo,

3.22. Mezcla de dos listas ordenadas

63

mezcla [1,3,5] [2,9] ; [1,2,3,5,9]


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

mezcla_1 :: Ord a => [a] mezcla_1 [] ys = mezcla_1 xs [] = mezcla_1 (x:xs) (y:ys) | x <= y = x | otherwise = y

-> [a] -> [a] ys xs : mezcla_1 xs (y:ys) : mezcla_1 (x:xs) ys

2. Denicin recursiva con inserta:

mezcla_2 :: Ord a => [a] -> [a] -> [a] mezcla_2 [] ys = ys mezcla_2 (x:xs) ys = inserta x (mezcla_2 xs ys)
3. Usaremos como mezcla la primera

mezcla :: Ord a => [a] -> [a] -> [a] mezcla = mezcla_1
Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> [Int] -> Bool prop_equivalencia xs ys = mezcla_1 xs ys == mezcla_2 xs ys


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


Las mezcla de listas ordenadas es una lista ordenada

prop_mezcla_ordenada :: [Int] -> [Int] -> Property prop_mezcla_ordenada xs ys = lista_ordenada xs && lista_ordenada ys ==> lista_ordenada (mezcla xs ys)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

64

Captulo 3. Estructuras de datos

3.23.

Ordenacin por mezcla

Ejercicio 3.23. Denir la funcin ordena_por_m tal que ordena_por_m l es la lista l ordenada mediante mezclas, Por ejemplo,

ordena_por_m [2,4,3,6,3] ; [2,3,3,4,6]


Solucin: Denicin recursiva

ordena_por_m :: Ord a => [a] -> [a] ordena_por_m [] = [] ordena_por_m [x] = [x] ordena_por_m xs = mezcla (ordena_por_m ys) (ordena_por_m zs) where medio = (length xs) `div` 2 ys = take medio xs zs = drop medio xs
El valor de ordena_por_m es una lista ordenada

prop_ordena_por_m_ordenada :: [Int] -> Bool prop_ordena_por_m_ordenada xs = lista_ordenada (ordena_por_m xs) PD> quickCheck prop_ordena_por_m_ordenada OK, passed 100 tests.

3.24.

Dgito correspondiente a un carcter numrico

Ejercicio 3.24. Denir la funcin dgitoDeCarcter tal que dgitoDeCarcter c es el dgito correspondiente al carcter numrico c. Por ejemplo,

dgitoDeCarcter '3' ; 3
Solucin:

dgitoDeCarcter :: Char -> Int dgitoDeCarcter c = ord c - ord '0'

3.25. Carcter correspondiente a un dgito

65

3.25.

Carcter correspondiente a un dgito

Ejercicio 3.25. Denir la funcin carcterDeDgito tal que carcterDeDgito n es el carcter correspondiente al dgito n. Por ejemplo,

carcterDeDgito 3 ; '3'
Solucin:

carcterDeDgito :: Int -> Char carcterDeDgito n = chr (n + ord '0')


La funcin carcterDeDgito es inversa de dgitoDeCarcter

prop_inversa :: Bool prop_inversa = and [dgitoDeCarcter(carcterDeDgito d)==d | d <- [0..9]]


Comprobacin

prop_inversa ; True

3.26.

Lista innita de nmeros

Ejercicio 3.26. Denir la funcin desde tal que desde n es la lista de los nmeros enteros a partir de n. Por ejemplo,

desde 5

; [5,6,7,8,9,10,11,12,13,14,{Interrupted!}

se interrumpe con Control-C. Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

desde_1 :: Int -> [Int] desde_1 n = n : desde_1 (n+1)


2. Denicin con segmento numrico:

desde_2 :: Int -> [Int] desde_2 n = [n..]


Las deniciones son equivalentes:

66

Captulo 3. Estructuras de datos

prop_equivalencia :: Int -> Int -> Bool prop_equivalencia n m = take m (desde_1 n) == take m (desde_2 n)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.27.

Lista con un elemento repetido

Ejercicio 3.27. Redenir la funcin repeat tal que repeat x es una lista innita con el nico elemento x. Por ejemplo,

repeat 'a' ; "aaaaaaaaaaaaaaaaaaaaaaaaaaa{Interrupted!}


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

n_repeat_1 :: a -> [a] n_repeat_1 x = x : n_repeat_1 x


2. Denicin recursiva con entorno local

n_repeat_2 :: a -> [a] n_repeat_2 x = xs where xs = x:xs


3. Denicin con lista de comprensin:

n_repeat_3 :: a -> [a] n_repeat_3 x = [x | y <- [1..]]


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Int -> Bool prop_equivalencia n m = take n (n_repeat_1 m) == take n (repeat m) && take n (n_repeat_2 m) == take n (repeat m) && take n (n_repeat_3 m) == take n (repeat m)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.28. Lista con un elemento repetido un nmero dado de veces

67

3.28.

Lista con un elemento repetido un nmero dado de veces

Ejercicio 3.28. Redenir la funcin replicate tal que replicate n x es una lista con n copias del elemento x. Por ejemplo,

replicate 10 3 ; [3,3,3,3,3,3,3,3,3,3] replicate (-10) 3 ; []


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

n_replicate_1 :: Int -> a -> [a] n_replicate_1 (n+1) x = x : n_replicate_1 n x n_replicate_1 _ x = []


2. Denicin por comprensin:

n_replicate_2 :: Int -> a -> [a] n_replicate_2 n x = [x | y <- [1..n]]


3. Denicin usando take y repeat:

n_replicate_3 :: Int -> a -> [a] n_replicate_3 n x = take n (repeat x)


Las deniciones son equivalentes:

prop_equivalencia prop_equivalencia n_replicate_1 n_replicate_2 n_replicate_3


Comprobacin

:: Int n m = n m == n m == n m ==

-> Int -> Bool replicate n m && replicate n m && replicate n m

Main> quickCheck prop_equivalencia OK, passed 100 tests.

68

Captulo 3. Estructuras de datos

3.29.

Iteracin de una funcin

Ejercicio 3.29. Redenir la funcin iterate tal que iterate f x es la lista cuyo primer elemento es x y los siguientes elementos se calculan aplicando la funcin f al elemento anterior. Por ejemplo,

iterate (+1) 3 ; [3,4,5,6,7,8,9,10,11,12,{Interrupted!} iterate (*2) 1 ; [1,2,4,8,16,32,64,{Interrupted!} iterate (`div` 10) 1972 ; [1972,197,19,1,0,0,0,0,0,0,{Interrupted!}
Solucin:

n_iterate :: (a -> a) -> a -> [a] n_iterate f x = x : n_iterate f (f x)


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Int -> Bool prop_equivalencia n m = take n (n_iterate (+1) m) == take n (iterate (+1) m)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.30.

Conversin de nmero entero a cadena

Ejercicio 3.30. Denir la funcin deEnteroACadena tal que deEnteroACadena n es la cadena correspondiente al nmero entero n. Por ejemplo,

deEnteroACadena 1972 ; "1972"


Solucin: Se presentan distintas deniciones: 1. Mediante composicin de funciones:

deEnteroACadena_1 :: Int -> String deEnteroACadena_1 = map carcterDeDgito . reverse . map (`rem` 10) . takeWhile (/= 0) . iterate (`div` 10)

3.31. Clculo de primos mediante la criba de Erasttenes Ejemplo de clculo

69

iterate (`div` 10) 1972 ; [1972,197,19,1,0,0,0,... (takeWhile (/= 0) . iterate (`div` 10)) 1972 ; [1972,197,19,1] map (`rem` 10) [1972,197,19,1] ; [2,7,9,1] reverse [2,7,9,1] ; [1,9,7,2] map carcterDeDgito [1,9,7,2] ; "1972"
2. Mediante la funcin show

deEnteroACadena_2 :: Int -> String deEnteroACadena_2 = show


Las deniciones son equivalentes:

prop_equivalencia :: Int -> Property prop_equivalencia n = n > 0 ==> deEnteroACadena_1 n == deEnteroACadena_2 n


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.31.

Clculo de primos mediante la criba de Erasttenes

Ejercicio 3.31. Denir la funcin primos_por_criba tal que primos_por_criba es la lista de los nmeros primos mediante la criba de Erasttenes.

primos_por_criba ; [2,3,5,7,11,13,17,19,23,29,{Interrupted!} take 10 primos_por_criba ; [2,3,5,7,11,13,17,19,23,29]


Solucin: Se presentan distintas deniciones: 1. Denicin perezosa:

primos_por_criba_1 :: [Int] primos_por_criba_1 = map head (iterate eliminar [2..]) where eliminar (x:xs) = filter (no_multiplo x) xs no_multiplo x y = y `mod` x /= 0
Para ver el clculo, consideramos la siguiente variacin

70

Captulo 3. Estructuras de datos

primos_por_criba_1_aux = map (take 10) (iterate eliminar [2..]) where eliminar (x:xs) = filter (no_multiplo x) xs no_multiplo x y = y `mod` x /= 0
Entonces,

Main> take 5 primos_por_criba_1_aux [[ 2, 3, 4, 5, 6, 7, 8, 9,10,11], [ 3, 5, 7, 9,11,13,15,17,19,21], [ 5, 7,11,13,17,19,23,25,29,31], [ 7,11,13,17,19,23,29,31,37,41], [11,13,17,19,23,29,31,37,41,43]]


2. Denicin por comprensin:

primos_por_criba_2 :: [Int] primos_por_criba_2 = criba [2..] where criba (p:xs) = p : criba [n | n<-xs, n `mod` p /= 0]
Las deniciones son equivalentes:

prop_equivalencia :: Int -> Bool prop_equivalencia n = take n primos_por_criba_1 == take n primos_por_criba_2


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.32.

Comprobacin de que todos los elementos son pares

Ejercicio 3.32. Denir la funcin todosPares tal que

todosPares xs se verica si todos los elementos de la lista xs son pares. Por ejemplo, todosPares [2,4,6] ; True todosPares [2,4,6,7] ; False
Solucin: Se presentan distintas deniciones:

3.33. Comprobacin de que todos los elementos son impares 1. Denicin recursiva:

71

todosPares_1 :: [Int] -> Bool todosPares_1 [] = True todosPares_1 (x:xs) = even x && todosPares_1 xs
2. Denicin con all:

todosPares_2 :: [Int] -> Bool todosPares_2 = all even


3. Denicin por comprensin:

todosPares_3 :: [Int] -> Bool todosPares_3 xs = ([x | x<-xs, even x] == xs)


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = todosPares_2 xs == todosPares_1 xs && todosPares_3 xs == todosPares_1 xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.33.

Comprobacin de que todos los elementos son impares

Ejercicio 3.33. Denir la funcin todosImpares tal que

todosImpares xs se verica si todos los elementos de la lista xs son impares. Por ejemplo, todosImpares [1,3,5] ; True todosImpares [1,3,5,6] ; False
Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

72

Captulo 3. Estructuras de datos

todosImpares_1 :: [Int] -> Bool todosImpares_1 [] = True todosImpares_1 (x:xs) = odd x && todosImpares_1 xs
2. Denicin con all:

todosImpares_2 :: [Int] -> Bool todosImpares_2 = all odd


3. Denicin por comprensin:

todosImpares_3 :: [Int] -> Bool todosImpares_3 xs = ([x | x<-xs, odd x] == xs)


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = todosImpares_2 xs == todosImpares_1 xs && todosImpares_3 xs == todosImpares_1 xs
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.34.

Tringulos numricos

Ejercicio 3.34. Denir la funcin tringulo tal que tringulo n es la lista de las lista de nmeros consecutivos desde [1] hasta [1,2,...,n. Por ejemplo,

tringulo 4 ; [[1],[1,2],[1,2,3],[1,2,3,4]]
Solucin: Denicin por comprensin:

tringulo :: Int -> [[Int]] tringulo n = [[1..x] | x <- [1..n]]

3.35. Posicin de un elemento en una lista

73

3.35.

Posicin de un elemento en una lista

Ejercicio 3.35. Denir la funcin posicin tal que posicin x ys es la primera posicin del elemento x en la lista ys y 0 en el caso de que no pertenezca a la lista. Por ejemplo,

posicin 5 [1,5,3,5,6,5,3,4] ; 2
Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

posicin_1 :: Eq a => a -> [a] -> Int posicin_1 x ys = if elem x ys then aux x ys else 0 where aux x [] = 0 aux x (y:ys) | x== y = 1 | otherwise = 1 + aux x ys
2. Denicin con listas de comprensin:

posicin_2 :: Eq a => a -> [a] -> Int posicin_2 x xs = head ([pos | (y,pos) <- zip xs [1..length xs], y == x] ++ [0])
Las deniciones son equivalentes:

prop_equivalencia :: Int -> [Int] -> Bool prop_equivalencia x xs = posicin_1 x xs == posicin_2 x xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


Usaremos como posicin la primera

posicin:: Eq a => a -> [a] -> Int posicin = posicin_1

74

Captulo 3. Estructuras de datos Se verica las siguiente propiedad: El elemento en la posicin de x en xs es x:

prop_posicin :: Int -> [Int] -> Bool prop_posicin x xs = let n=posicin x xs in if n==0 then notElem x xs else xs!!(n-1)==x

3.36.

Ordenacin rpida

Ejercicio 3.36. Denir la funcin ordenaR tal que ordenaR xs es la lista xs ordenada mediante el procedimiento de ordenacin rpida. Por ejemplo,

ordenaR [5,2,7,7,5,19,3,8,6] ; [2,3,5,5,6,7,7,8,19]


Solucin:

ordenaR :: Ord a => [a] -> [a] ordenaR [] = [] ordenaR (x:xs) = ordenaR menores ++ [x] ++ ordenaR mayores where menores = [e | e<-xs, e<x] mayores = [e | e<-xs, e>=x]
El valor de ordenaR es una lista ordenada

prop_ordenaR_ordenada :: [Int] -> Bool prop_ordenaR_ordenada xs = lista_ordenada (ordenaR xs) Ordena_por_insercion> quickCheck prop_ordenaR_ordenada OK, passed 100 tests.

3.37.

Primera componente de un par

Ejercicio 3.37. Redenir la funcin fst tal que fst p es la primera componente del par p. Por ejemplo,

fst (3,2) ; 3
Solucin:

3.38. Segunda componente de un par

75

n_fst :: (a,b) -> a n_fst (x,_) = x


Las deniciones son equivalentes:

prop_equivalencia :: (Int,Int) -> Bool prop_equivalencia p = n_fst p == fst p


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.38.

Segunda componente de un par

Ejercicio 3.38. Redenir la funcin snd tal que snd p es la segunda componente del par p. Por ejemplo,

snd (3,2) ; 2
Solucin:

n_snd :: (a,b) -> b n_snd (_,y) = y


Las deniciones son equivalentes:

prop_equivalencia :: (Int,Int) -> Bool prop_equivalencia p = n_snd p == snd p


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

76

Captulo 3. Estructuras de datos

3.39.

Componentes de una terna

Ejercicio 3.39. Redenir las siguientes funciones

fst3 t es la primera componente de la terna t. snd3 t es la segund componente de la terna t. thd3 t es la tercera componente de la terna t.
Por ejemplo,

fst3 (3,2,5) ; 3 snd3 (3,2,5) ; 2 thd3 (3,2,5) ; 5


Solucin:

n_fst3 :: (a,b,c) -> a n_fst3 (x,_,_) = x n_snd3 :: (a,b,c) -> b n_snd3 (_,y,_) = y n_thd3 :: (a,b,c) -> c n_thd3 (_,_,z) = z
Se verica la siguiente propiedad:

prop_ternas :: (Int,Int,Int) -> Bool prop_ternas x = (n_fst3 x, n_snd3 x, n_thd3 x) == x


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.40.

Creacin de variables a partir de pares

Ejercicio 3.40. Denir la funcin variable tal que variable p es la cadena correspondiente al par p formado por un carcter y un nmero. Por ejemplo,

variable ('x',3) ; "x3"

3.41. Divisin de una lista Solucin:

77

variable :: (Char,Int) -> String variable (c,n) = [c] ++ show n

3.41.

Divisin de una lista

Ejercicio 3.41. Redenir la funcin splitAt tal que splitAt n l es el par formado por la lista de los n primeros elementos de la lista l y la lista l sin los n primeros elementos. Por ejemplo,

splitAt 3 [5,6,7,8,9,2,3] ; ([5,6,7],[8,9,2,3]) splitAt 4 "sacacorcho" ; ("saca","corcho")


Solucin:

n_splitAt n_splitAt n_splitAt n_splitAt where

:: Int -> [a] -> ([a], [a]) n xs | n <= 0 = ([],xs) _ [] = ([],[]) n (x:xs) = (x:xs',xs'') (xs',xs'') = n_splitAt (n-1) xs

Se verica la siguiente propiedad:

prop_splitAt :: Int -> [Int] -> Bool prop_splitAt n xs = n_splitAt n xs == (take n xs, drop n xs)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.42.

Sucesin de Fibonacci

Ejercicio 3.42. Denir la funcin fib n tal que fib n es el nsimo trmino de la sucesin de Fibonacci 1,1,2,3,5,8,13,21,34,55,. . . Por ejemplo,

fib 5

valor

Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

78

Captulo 3. Estructuras de datos

fib_1 fib_1 fib_1 fib_1

:: Int -> Int 0 = 1 1 = 1 (n+2) = fib_1 n + fib_1 (n+1)

2. Denicin con acumuladores:

fib_2 :: Int -> Int fib_2 n = fib_2_aux n 1 1 where fib_2_aux 0 p q = p fib_2_aux (n+1) p q = fib_2_aux n q (p+q)
3. Denicin con mediante listas innitas:

fib_3 :: Int -> Int fib_3 n = fibs!!n


donde fibs es la sucesin de los nmeros de Fibonacci.

fibs :: [Int] fibs = 1 : 1 : [a+b | (a,b) <- zip fibs (tail fibs)]
Las deniciones son equivalentes:

prop_equivalencia :: Bool prop_equivalencia = [fib_1 n | n <- [1..20]] == [fib_2 n | n <- [1..20]] && [fib_3 n | n <- [1..20]] == [fib_2 n | n <- [1..20]]
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


La complejidad de fib_1 es O( f ib(n)) y la de fib_2 y fib_3 es O(n), como se observa en la siguiente tabla donde se muestra el nmero de reducciones n fib_1 fib_2 fib_3 2 85 96 76 4 241 158 114 8 1.741 282 190 16 82.561 530 342 32 182.249.581 1.026 706

3.43. Incremento con el mnimo

79

3.43.

Incremento con el mnimo

Ejercicio 3.43. Denir la funcin incmin tal que incmin l es la lista obtenida aadiendo a cada elemento de l el menor elemento de l. Por ejemplo,

incmin [3,1,4,1,5,9,2,6] ; [4,2,5,2,6,10,3,7]


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva

incmin_1 :: [Int] -> [Int] incmin_1 l = map (+e) l where e = mnimo l mnimo [x] = x mnimo (x:y:xs) = min x (mnimo (y:xs))
2. Con la denicin anterir se recorre la lista dos veces: una para calcular el mnimo y otra para sumarlo. Con la siguiente denicin la lista se recorre slo una vez.

incmin_2 :: [Int] -> [Int] incmin_2 [] = [] incmin_2 l = nuevalista where (minv, nuevalista) = un_paso l un_paso [x] = (x, [x+minv]) un_paso (x:xs) = (min x y, (x+minv):ys) where (y,ys) = un_paso xs
Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = incmin_1 xs == incmin_2 xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

80

Captulo 3. Estructuras de datos

3.44.

Longitud de camino entre puntos bidimensionales

Ejercicio 3.44. Denir el tipo Punto como un par de nmeros reales Por ejemplo,

(3.0,4.0) :: Punto
Solucin:

type Punto = (Double, Double)


Ejercicio 3.45. Denir la funcin distancia_al_origen tal que distancia_al_origen p es la distancia del punto p al origen. Por ejemplo,

distancia_al_origen (3,4) ; 5.0


Solucin:

distancia_al_origen :: Punto -> Double distancia_al_origen (x,y) = sqrt (x*x+y*y)


Ejercicio 3.46. Denir la funcin distancia tal que distancia p1 p2 es la distancia entre los puntos p1 y p2. Por ejemplo,

distancia (2,4) (5,8) ; 5.0


Solucin:

distancia :: Punto -> Punto -> Double distancia (x,y) (x',y') = sqrt((x-x')^2+(y-y')^2)
Ejercicio 3.47. Denir el tipo Camino como una lista de puntos Por ejemplo,

[(1,2),(4,6),(7,10)] :: Camino
Solucin:

type Camino = [Punto]


Ejercicio 3.48. Denir la funcin longitud_camino tal que longitud_camino c es la longitud del camino c. Por ejemplo,

longitud_camino [(1,2),(4,6),(7,10)] ; 10.0


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

3.45. Nmeros racionales

81

longitud_camino_1 :: Camino -> Double longitud_camino_1 (x:y:xs) = distancia x y + longitud_camino_1 (y:xs) longitud_camino_1 _ = 0
2. Denicin por comprensin:

longitud_camino_2 :: Camino -> Double longitud_camino_2 xs = sum [distancia p q | (p,q) <- zip (init xs) (tail xs)]
Evaluacin paso a paso:

longitud_camino_2 [(1,2),(4,6),(7,10)] = sum [distancia p q | (p,q) <- zip (init [(1,2),(4,6),(7,10)]) (tail [(1,2),(4,6),(7,10)])] = sum [distancia p q | (p,q) <- zip [(1,2),(4,6)] [(4,6),(7,10)]] = sum [distancia p q | (p,q) <- [((1,2),(4,6)),((4,6),(7,10))]] = sum [5.0,5.0] = 10
Las deniciones son equivalentes:

prop_equivalencia xs = not (null xs) ==> longitud_camino_1 xs ~= longitud_camino_2 xs infix 4 ~= (~=) :: Double -> Double -> Bool x ~= y = abs(x-y) < 0.0001
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.45.
Solucin:

Nmeros racionales

Ejercicio 3.49. Denir el tipo Racional de los nmeros racionales como pares de enteros.

82

Captulo 3. Estructuras de datos

type Racional = (Int, Int)


Ejercicio 3.50. Denir la funcin simplificar tal que simplificar x es el nmero racional x simplicado. Por ejemplo,

simplificar simplificar simplificar simplificar


Solucin:

(12,24) (12,-24) (-12,-24) (-12,24)

; ; ; ;

(1,2) (-1,2) (1,2) (-1,2)

simplificar (n,d) = (((signum d)*n) `div` m, (abs d) `div` m) where m = gcd n d


Ejercicio 3.51. Denir las operaciones entre nmeros racionales qMul, qDiv, qSum y qRes. Por ejemplo,

qMul qDiv qSum qRes

(1,2) (1,2) (1,2) (1,2)

(2,3) (1,4) (3,4) (3,4)

; ; ; ;

(1,3) (2,1) (5,4) (-1,4)

Solucin:

qMul :: Racional -> Racional -> Racional qMul (x1,y1) (x2,y2) = simplificar (x1*x2, y1*y2) qDiv :: Racional -> Racional -> Racional qDiv (x1,y1) (x2,y2) = simplificar (x1*y2, y1*x2) qSum :: Racional -> Racional -> Racional qSum (x1,y1) (x2,y2) = simplificar (x1*y2+y1*x2, y1*y2) qRes :: Racional -> Racional -> Racional qRes (x1,y1) (x2,y2) = simplificar (x1*y2-y1*x2, y1*y2)
Ejercicio 3.52. Denir la funcin escribeRacional tal que escribeRacional x es la cadena correspodiente al nmero racional x. Por ejemplo,

escribeRacional (10,12) ; "5/6" escribeRacional (12,12) ; "1" escribeRacional (qMul (1,2) (2,3)) ; "1/3"

3.46. Mximo comn divisor Solucin:

83

escribeRacional :: Racional -> String escribeRacional (x,y) | y' == 1 = show x' | otherwise = show x' ++ "/" ++ show y' where (x',y') = simplificar (x,y)

3.46.

Mximo comn divisor

Ejercicio 3.53. Redenir la funcin gcd tal que gcd x y es el mximo comn divisor de x e y. Por ejemplo,

gcd 6 15 ; 3
Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

n_gcd_1 :: Int -> Int -> Int n_gcd_1 0 0 = error "gcd 0 0 no est definido" n_gcd_1 x y = n_gcd_1' (abs x) (abs y) where n_gcd_1' x 0 = x n_gcd_1' x y = n_gcd_1' y (x `rem` y)
2. Denicin con divisible y divisores

n_gcd_2 n_gcd_2 n_gcd_2 n_gcd_2

:: Int -> Int -> Int 0 0 = error "gcd 0 0 no est definido" 0 y = abs y x y = last (filter (divisible y') (divisores x')) where x' = abs x y' = abs y divisores x = filter (divisible x) [1..x] divisible x y = x `rem` y == 0

Las deniciones son equivalentes:

prop_equivalencia :: Int -> Int -> Property prop_equivalencia x y = (x,y) /= (0,0) ==> n_gcd_1 x y == gcd x y && n_gcd_2 x y == gcd x y

84 Comprobacin

Captulo 3. Estructuras de datos

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.47.

Bsqueda en una lista de asociacin

Ejercicio 3.54. Redenir la funcin lookup tal que lookup l z es el valor del primer elemento de la lista de bsqueda l cuya clave es z. Por ejemplo,

lookup [('a',1),('b',2),('c',3),('b',4)] 'b' ; 2


Solucin:

n_lookup :: Eq a => a -> [(a,b)] -> Maybe b n_lookup k [] = Nothing n_lookup k ((x,y):xys) | k==x = Just y | otherwise = n_lookup k xys
Las deniciones son equivalentes:

prop_equivalencia :: Int -> [(Int,Int)] -> Bool prop_equivalencia z xys = n_lookup z xys == n_lookup z xys
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


Se verica la siguiente propiedad

prop_lookup :: Int -> Int -> [(Int,Int)] -> Bool prop_lookup x y xys = if n_lookup x xys == Just y then elem (x,y) xys else notElem (x,y) xys
Sin embargo, no es cierta la siguiente

prop_lookup_falsa prop_lookup_falsa if elem (x,y) else n_lookup

:: Int -> Int -> [(Int,Int)] -> Bool x y xys = xys then n_lookup x xys == Just y x xys == Nothing

3.48. Emparejamiento de dos listas En efecto,

85

Main> quickCheck prop_lookup_falsa Falsifiable, after 0 tests: -2 1 [(-2,-2)]

3.48.

Emparejamiento de dos listas

Ejercicio 3.55. Redenir la funcin zip tal que zip x y es la lista obtenida emparejando los correspondientes elementos de x e y. Por ejemplo,

zip [1,2,3] "abc" ; [(1,'a'),(2,'b'),(3,'c')] zip [1,2] "abc" ; [(1,'a'),(2,'b')]


Solucin: Se presentan distintas deniciones: 1. Denicin recursiva

n_zip_1 :: [a] -> [b] -> [(a,b)] n_zip_1 (x:xs) (y:ys) = (x,y) : zip xs ys n_zip_1 _ _ = []
2. Denicin con zipWith

n_zip_2 :: [a] -> [b] -> [(a,b)] n_zip_2 = zipWith (\x y -> (x,y))
Las deniciones son equivalentes:

prop_equivalencia prop_equivalencia n_zip_1 xs xs n_zip_2 xs xs


Comprobacin

:: xs == ==

[Int] -> Bool = zip xs xs && zip xs xs

Main> quickCheck prop_equivalencia OK, passed 100 tests.

86

Captulo 3. Estructuras de datos

3.49.

Emparejamiento funcional de dos listas

Ejercicio 3.56. Redenir la funcin zipWith tal que zipWith f x y es la lista obtenida aplicando la funcin f a los elementos correspondientes de las listas x e y. Por ejemplo,

zipWith (+) [1,2,3] [4,5,6] ; [5,7,9] zipWith (*) [1,2,3] [4,5,6] ; [4,10,18]
Solucin:

n_zipWith :: (a->b->c) -> [a]->[b]->[c] n_zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys n_zipWith _ _ _ = []


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Bool prop_equivalencia xs = n_zipWith (+) xs xs == zipWith (+) xs xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

3.50.

Curricacin

Ejercicio 3.57. Una funcin est en forma cartesiana si su argumento es una tupla. Por ejemplo,

suma_cartesiana :: (Int,Int) -> Int suma_cartesiana (x,y) = x+y


En cambio, la funcin

suma_currificada :: Int -> Int -> Int suma_currificada x y = x+y


est en forma curricada. Redenir la funcin curry tal que curry f es la versin curricada de la funcin f. Por ejemplo,

curry suma_cartesiana 2 3 ; 5

3.51. Funciones sobre rboles

87

y la funcin uncurry tal que uncurry f es la versin cartesiana de la funcin f. Por ejemplo,

uncurry suma_currificada (2,3) ; 5


Solucin:

n_curry :: ((a,b) -> c) -> (a -> b -> c) n_curry f x y = f (x,y) n_uncurry :: (a -> b -> c) -> ((a,b) -> c) n_uncurry f p = f (fst p) (snd p)

3.51.

Funciones sobre rboles

Ejercicio 3.58. Un rbol de tipo a es una hoja de tipo a o es un nodo de tipo a con dos hijos que son rboles de tipo a. Denir el tipo rbol. Solucin:

data rbol a = Hoja | Nodo a (rbol a) (rbol a) deriving Show


Ejercicio 3.59. Denir el rbol correspondiente a la siguiente gura

Solucin:

88

Captulo 3. Estructuras de datos

ejrbol_1 = Nodo 4 (Nodo 2 (Nodo (Nodo (Nodo 6 (Nodo (Nodo

1 3 5 7

Hoja Hoja Hoja Hoja

Hoja) Hoja)) Hoja) Hoja))

Ejercicio 3.60. Denir la funcin tamao tal que tamao a es el tamao del rbol a; es decir, el nmero de nodos internos. Por ejemplo,

tamao ejrbol_1 ; 7
Solucin:

tamao :: rbol a -> Int tamao Hoja = 0 tamao (Nodo x a1 a2) = 1 + tamao a1 + tamao a2
Ejercicio 3.61. Un rbol de bsqueda es un rbol binario en el que que todos los valores en el subrbol izquierdo son menores que el valor en el nodo mismo, y que todos los valores en el subrbol derecho son mayores. Por ejemplo, el ejrbol_1 es un rbol de bsqueda. Denir la funcin elemrbol tal que elemrbol e x se verica si e es un elemento del rbol de bqueda x. Por ejemplo,

elemrbol 5 ejrbol_1 ; True elemrbol 9 ejrbol_1 ; False


Solucin:

elemrbol :: Ord a => a -> rbol a -> elemrbol e Hoja = False elemrbol e (Nodo x izq der) | e==x = | e<x = | e>x =

Bool True elemrbol e izq elemrbol e der

Ejercicio 3.62. Denir la funcin insertarbol tal que insertarbol e ab inserta el elemento e en el rbol de bsqueda ab. Por ejemplo,

Main> insertarbol Nodo 4 (Nodo 2 (Nodo (Nodo (Nodo 6 (Nodo

8 ejrbol_1 1 Hoja Hoja) 3 Hoja Hoja)) 5 Hoja Hoja)

3.51. Funciones sobre rboles

89

(Nodo 7 Hoja (Nodo 8 Hoja Hoja))) Main> insertarbol 3 ejrbol_1 Nodo 4 (Nodo 2 (Nodo 1 Hoja Hoja) (Nodo 3 (Nodo 3 Hoja Hoja) Hoja)) (Nodo 6 (Nodo 5 Hoja Hoja) (Nodo 7 Hoja Hoja))
Solucin:

insertarbol insertarbol insertarbol | e <= x | e > x

:: Ord a => a -> rbol a -> rbol a e Hoja = Nodo e Hoja Hoja e (Nodo x izq der) = Nodo x (insertarbol e izq) der = Nodo x izq (insertarbol e der)

Ejercicio 3.63. Denir la funcin listarbol tal que listarbol l es el rbol de bsqueda obtenido a partir de la lista l. Por ejemplo,

Main> listarbol [3,2,4,1] Nodo 1 Hoja (Nodo 4 (Nodo 2 Hoja (Nodo 3 Hoja Hoja)) Hoja)
Solucin:

listarbol :: Ord a => [a] -> rbol a listarbol = foldr insertarbol Hoja
Ejercicio 3.64. Denir la funcin aplana tal que aplana ab es la lista obtenida aplanando el rbol ab. Por ejemplo,

aplana ejrbol_1 ; [1,2,3,4,5,6,7] aplana (listarbol [3,2,4,1]) ; [1,2,3,4]

90 Solucin:

Captulo 3. Estructuras de datos

aplana :: rbol a -> [a] aplana Hoja = [] aplana (Nodo x izq der) = aplana izq ++ [x] ++ aplana der
Ejercicio 3.65. Denir la funcin ordenada_por_rbol tal que ordenada_por_rbol l es la lista l ordenada mediante rbol de bsqueda. Por ejemplo,

ordenada_por_rbol [1,4,3,7,2] ; [1,2,3,4,7]


Solucin:

ordenada_por_rbol :: Ord a => [a] -> [a] ordenada_por_rbol = aplana . listarbol


Se verica la siguiente propiedad

prop_ordenada_por_rbol :: [Int] -> Bool prop_ordenada_por_rbol xs = lista_ordenada (ordenada_por_rbol xs)


En efecto,

Main> quickCheck prop_ordenada_por_arbol OK, passed 100 tests.

3.52.

Bsqueda en lista ordenada

Ejercicio 3.66. Denir la funcin elem_ord tal que elem_ord e l se verica si e es un elemento de la lista ordenada l. Por ejemplo,

elem_ord 3 [1,3,5] ; True elem_ord 2 [1,3,5] ; False


Solucin:

elem_ord :: Ord a => a -> [a] -> Bool elem_ord _ [] = False elem_ord e (x:xs) | x < e = elem_ord e xs | x == e = True | otherwise = False

3.53. Movimiento segn las direcciones

91

3.53.

Movimiento segn las direcciones

Ejercicio 3.67. Denir el tipo nito Direccim tal que sus constructores son Norte, Sur, Este y Oeste. Solucin:

data Direccin = Norte | Sur | Este | Oeste


Ejercicio 3.68. Denir la funcin mueve tal que mueve d p es el punto obtenido moviendo el punto p una unidad en la direccin d. Por ejemplo,

mueve Sur (mueve Este (4,7)) ; (5,6)


Solucin:

mueve mueve mueve mueve mueve

:: Direccin -> (Int,Int) -> (Int,Int) Norte (x,y) = (x,y+1) Sur (x,y) = (x,y-1) Este (x,y) = (x+1,y) Oeste (x,y) = (x-1,y)

3.54.

Los racionales como tipo abstracto de datos

Ejercicio 3.69. Denir el tipo de datos Ratio para representar los racionales como un par de enteros (su numerador y denominador). Solucin:

data Ratio =

Rac Int Int

Ejercicio 3.70. Denir Ratio como una instancia de Show de manera que la funcin show muestra la forma simplicada obtenida mediante la funcin simplificarRatio tal que simplificarRatio x es el nmero racional x simplicado. Por ejemplo,

simplificarRatio simplificarRatio simplificarRatio simplificarRatio


Solucin:

(Rac 12 (Rac 12 (Rac -12 (Rac -12

24) -24) -24) 24)

; 1/2 ; -1/2 ; 1/2 ; -1/2

92

Captulo 3. Estructuras de datos

instance Show Ratio where show (Rac x 1) = show x show (Rac x y) = show x' ++ "/" ++ show y' where (Rac x' y') = simplificarRatio (Rac x y) simplificarRatio :: Ratio -> Ratio simplificarRatio (Rac n d) = Rac (((signum d)*n) `div` m) ((abs d) `div` m) where m = gcd n d
Ejercicio 3.71. Denir los nmeros racionales 0, 1, 2, 3, 1/2, 1/3 y 1/4. Por ejemplo,

Main> :set +t Main> rDos 2 :: Ratio Main> rTercio 1/3 :: Ratio


Solucin:

rCero rUno rDos rTres rMedio rTercio rCuarto

= = = = = = =

Rac Rac Rac Rac Rac Rac Rac

0 1 2 3 1 1 1

1 1 1 1 2 3 4

Ejercicio 3.72. Denir las operaciones entre nmeros racionales rMul, rDiv, rSum y rRes. Por ejemplo,

rMul rDiv rSum rRes

(Rac (Rac (Rac (Rac

1 1 1 1

2) 2) 2) 2)

(Rac (Rac (Rac (Rac

2 1 3 3

3) 4) 4) 4)

; 1/3 ; 2 ; 5/4 ; -1/4

Solucin:

rMul :: Ratio -> Ratio -> Ratio rMul (Rac a b) (Rac c d) = simplificarRatio (Rac (a*c) (b*d)) rDiv :: Ratio -> Ratio -> Ratio rDiv (Rac a b) (Rac c d) = simplificarRatio (Rac (a*d) (b*c))

3.54. Los racionales como tipo abstracto de datos

93

rSum :: Ratio -> Ratio -> Ratio rSum (Rac a b) (Rac c d) = simplificarRatio (Rac (a*d+b*c) (b*d)) rRes :: Ratio -> Ratio -> Ratio rRes (Rac a b) (Rac c d) = simplificarRatio (Rac (a*d-b*c) (b*d))

94

Captulo 3. Estructuras de datos

Captulo 4 Aplicaciones de programacin funcional


Contenido
4.1. Segmentos iniciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 4.2. Segmentos nales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 4.3. Segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 4.4. Sublistas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 4.5. Comprobacin de subconjunto . . . . . . . . . . . . . . . . . . . . . . . . 97 4.6. Comprobacin de la igualdad de conjuntos . . . . . . . . . . . . . . . . 98 4.7. Permutaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 4.8. Combinaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 4.9. El problema de las reinas . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 4.10. Nmeros de Hamming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

4.1.

Segmentos iniciales

Ejercicio 4.1. Denir la funcin iniciales tal que iniciales l es la lista de los segmentos iniciales de la lista l. Por ejemplo,

iniciales [2,3,4] ; [[],[2],[2,3],[2,3,4]] iniciales [1,2,3,4] ; [[],[1],[1,2],[1,2,3],[1,2,3,4]]


Solucin:

iniciales :: [a] -> [[a]] iniciales [] = [[]] iniciales (x:xs) = [] : [x:ys | ys <- iniciales xs]
95

96

Captulo 4. Aplicaciones de programacin funcional

El nmero de los segmentos iniciales es el nmero de los elementos de la lista ms uno.

prop_iniciales :: [Int] -> Bool prop_iniciales xs = length(iniciales xs) == 1 + length xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

4.2.

Segmentos nales

Ejercicio 4.2. Denir la funcin finales tal que finales l es la lista de los segmentos nales de la lista l. Por ejemplo,

finales [2,3,4] ; [[2,3,4],[3,4],[4],[]] finales [1,2,3,4] ; [[1,2,3,4],[2,3,4],[3,4],[4],[]]


Solucin:

finales :: [a] -> [[a]] finales [] = [[]] finales (x:xs) = (x:xs) : finales xs
El nmero de los segmentos nales es el nmero de los elementos de la lista ms uno.

prop_finales :: [Int] -> Bool prop_finales xs = length(finales xs) == 1 + length xs


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

4.3. Segmentos

97

4.3.

Segmentos

Ejercicio 4.3. Denir la funcin segmentos tal que segmentos l es la lista de los segmentos de la lista l. Por ejemplo,

Main> segmentos [2,3,4] [[],[4],[3],[3,4],[2],[2,3],[2,3,4]] Main> segmentos [1,2,3,4] [[],[4],[3],[3,4],[2],[2,3],[2,3,4],[1],[1,2],[1,2,3],[1,2,3,4]]


Solucin:

segmentos :: [a] -> [[a]] segmentos [] = [[]] segmentos (x:xs) = segmentos xs ++ [x:ys | ys <- iniciales xs]

4.4.

Sublistas

Ejercicio 4.4. Denir la funcin sublistas tal que sublistas l es la lista de las sublistas de la lista l. Por ejemplo,

Main> sublistas [2,3,4] [[2,3,4],[2,3],[2,4],[2],[3,4],[3],[4],[]] Main> sublistas [1,2,3,4] [[1,2,3,4],[1,2,3],[1,2,4],[1,2],[1,3,4],[1,3],[1,4],[1], [2,3,4], [2,3], [2,4], [2], [3,4], [3], [4], []]
Solucin:

sublistas :: [a] -> [[a]] sublistas [] = [[]] sublistas (x:xs) = [x:ys | ys <- sub] ++ sub where sub = sublistas xs

4.5.

Comprobacin de subconjunto

Ejercicio 4.5. Denir la funcin subconjunto tal que subconjunto xs ys se verica si xs es un subconjunto de ys. Por ejemplo,

subconjunto [1,3,2,3] [1,2,3] ; True subconjunto [1,3,4,3] [1,2,3] ; False

98

Captulo 4. Aplicaciones de programacin funcional

Solucin: Se presentan distintas deniciones: 1. Denicin recursiva:

subconjunto_1 :: Eq a => [a] -> [a] -> Bool subconjunto_1 [] _ = True subconjunto_1 (x:xs) ys = elem x ys && subconjunto_1 xs ys
2. Denicin mediante all:

subconjunto_2 :: Eq a => [a] -> [a] -> Bool subconjunto_2 xs ys = all (`elem` ys) xs
3. Usaremos como subconjunto la primera

subconjunto :: Eq a => [a] -> [a] -> Bool subconjunto = subconjunto_1


Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> [Int] -> Bool prop_equivalencia xs ys = subconjunto_1 xs ys == subconjunto_2 xs ys


Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.

4.6.

Comprobacin de la igualdad de conjuntos

Ejercicio 4.6. Denir la funcin igual_conjunto tal que igual_conjunto l1 l2 se verica si las listas l1 y l2 vistas como conjuntos son iguales Por ejemplo,

igual_conjunto [1..10] [10,9..1] ; True igual_conjunto [1..10] [11,10..1] ; False


Solucin: Se presentan distintas deniciones: 1. Usando subconjunto

igual_conjunto_1 :: Eq a => [a] -> [a] -> Bool igual_conjunto_1 xs ys = subconjunto xs ys && subconjunto ys xs

4.7. Permutaciones 2. Por recursin.

99

igual_conjunto_2 :: Eq a => [a] -> [a] -> Bool igual_conjunto_2 xs ys = aux (nub xs) (nub ys) where aux [] [] = True aux (x:_) [] = False aux [] (y:_) = False aux (x:xs) ys = x `elem` ys && aux xs (delete x ys)
3. Usando sort

igual_conjunto_3 :: (Eq a, Ord a) => [a] -> [a] -> Bool igual_conjunto_3 xs ys = sort (nub xs) == sort (nub ys)
4. Usaremos como igual_conjunto la primera

igual_conjunto :: Eq a => [a] -> [a] -> Bool igual_conjunto = igual_conjunto_1


Las deniciones son equivalentes:

prop_equivalencia :: prop_equivalencia xs igual_conjunto_2 igual_conjunto_3


Comprobacin

[Int] -> [Int] -> Bool ys = xs ys == igual_conjunto_1 xs ys && xs ys == igual_conjunto_1 xs ys

Main> quickCheck prop_equivalencia OK, passed 100 tests.

4.7.

Permutaciones

Ejercicio 4.7. Denir la funcin permutaciones tal que permutaciones l es la lista de las permutaciones de la lista l. Por ejemplo,

Main> permutaciones [2,3] [[2,3],[3,2]] Main> permutaciones [1,2,3] [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]


Solucin: Se presentan distintas deniciones:

100 1. Por eleccin y recursin:

Captulo 4. Aplicaciones de programacin funcional

import Data.List ((\\)) permutaciones_1 :: Eq a => [a] -> [[a]] permutaciones_1 [] = [[]] permutaciones_1 xs = [a:p | a <- xs, p <- permutaciones_1(xs \\ [a])]
2. Por recursin e intercalacin:

permutaciones_2 :: [a] -> [[a]] permutaciones_2 [] = [[]] permutaciones_2 (x:xs) = [zs | ys <- permutaciones_2 xs, zs <- intercala x ys]
donde intercala x ys es la lista de las listas obtenidas intercalando x entre los elementos de la lista l. Por ejemplo,

intercala 1 [2,3] ; [[1,2,3],[2,1,3],[2,3,1]] intercala :: a -> [a] -> [[a]] intercala e [] = [[e]] intercala e (x:xs) = (e:x:xs) : [(x:ys) | ys <- (intercala e xs)]
Las deniciones son equivalentes:

prop_equivalencia :: [Int] -> Property prop_equivalencia xs = length xs <= 6 ==> igual_conjunto (permutaciones_1 xs) (permutaciones_2 xs)
Comprobacin

Main> quickCheck prop_equivalencia OK, passed 100 tests.


El nmero de permutaciones de un conjunto de n elementos es el factorial de n.

prop_nmero_permutaciones :: [Int] -> Property prop_nmero_permutaciones xs = length xs <= 6 ==> length (permutaciones_2 xs) == factorial (length xs) where factorial n = product [1..n]

4.8. Combinaciones

101

En la propiedades hemos acotado la longitude mxima de las listas generadas para facilitar los clculos. La segunda denicin es ms eciente: n permutaciones_1 permutaciones_2 2 140 102 3 334 172 4 1.170 428 5 5.656 1.740 6 34.192 10.036 7 243.744 71.252 donde las columnas segunda y tercera contiene el nmero de reducciones.

4.8.

Combinaciones

Ejercicio 4.8. Denir la funcin combinaciones tal que combinaciones n l es la lista de las combinaciones narias de la lista l. Por ejemplo,

combinaciones 2 [1,2,3,4] ; [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]


Solucin: Se presentan distintas deniciones: 1. Denicin mediante sublistas:

combinaciones_1 :: Int -> [a] -> [[a]] combinaciones_1 n xs = [ys | ys <- sublistas xs, length ys == n]
2. Denicin directa:

combinaciones_2 combinaciones_2 combinaciones_2 combinaciones_2

:: Int -> [a] -> [[a]] 0 _ = [[]] _ [] = [] (n+1) (x:xs) = [x:ys | ys <- combinaciones_2 n xs] ++ combinaciones_2 (n+1) xs

La segunda denicin es ms eciente como se comprueba en la siguiente sesin

Main> :set +s Main> length (combinaciones_1 2 [1..15]) 105 (1917964 reductions, 2327983 cells, 3 garbage collections) Main> length (combinaciones_2 2 [1..15]) 105 (6217 reductions, 9132 cells)

102

Captulo 4. Aplicaciones de programacin funcional

4.9.

El problema de las reinas

Ejercicio 4.9. El problema de las N reinas consiste en colocar N reinas en un tablero rectangular de dimensiones N por N de forma que no se encuentren ms de una en la misma lnea: horizontal, vertical o diagonal. Denir la funcin reinas tal que reinas n es la lista de las soluciones del problema de las N reinas. Por ejemplo,

reinas 4 ; [[3,1,4,2],[2,4,1,3]]
La primera solucin [3,1,4,2] se interpreta como R R R R Solucin: Se importa la diferencia de conjuntos (\\) del mdulo List:

import Data.List ((\\))


El tablero se representa por una lista de nmeros que indican las las donde se han colocado las reinas. Por ejemplo, [3,5] indica que se han colocado las reinas (1,3) y (2,5).

type Tablero = [Int]


La denicin de reinas es

reinas :: Int -> [Tablero] reinas n = reinasAux n where reinasAux 0 = [[]] reinasAux (m+1) = [r:rs | rs <- reinasAux m, r <- ([1..n] \\ rs), noAtaca r rs 1]
donde noAtaca r rs d se verica si la reina r no ataca a niguna de las de la lista rs donde la primera de la lista est a una distancia horizontal d.

noAtaca :: Int -> Tablero -> Int -> Bool noAtaca _ [] _ = True noAtaca r (a:rs) distH = abs(r-a) /= distH && noAtaca r rs (distH+1)

4.10. Nmeros de Hamming

103

4.10.

Nmeros de Hamming

Ejercicio 4.10. Los nmeros de Hamming forman una sucesin estrictamente creciente de nmeros que cumplen las siguientes condiciones: 1. El nmero 1 est en la sucesin. 2. Si x est en la sucesin, entonces 2 x, 3 x y 5 x tambin estn. 3. Ningn otro nmero est en la sucesin. Denir la funcin hamming tal que hamming es la sucesin de Hamming. Por ejemplo,

take 15 hamming ; [1,2,3,4,5,6,8,9,10,12,15,16,18,20,24]


Solucin:

hamming :: [Int] hamming = 1 : mezcla3 [2*i | i <- hamming] [3*i | i <- hamming] [5*i | i <- hamming]
donde mezcla3 xs ys zs es la lista obtenida mezclando las listas ordenadas xs, ys y zs y eliminando los elementos duplicados. Por ejemplo,

mezcla3 [2,4,6,8,10] [3,6,9,12] [5,10] ; [2,3,4,5,6,8,9,10,12] mezcla3 :: [Int] -> [Int] -> [Int] -> [Int] mezcla3 xs ys zs = mezcla2 xs (mezcla2 ys zs)
y mezcla2 xs ys zs es la lista obtenida mezclando las listas ordenadas xs e ys y eliminando los elementos duplicados. Por ejemplo,

mezcla2 [2,4,6,8,10,12] [3,6,9,12] ; [2,3,4,6,8,9,10,12] mezcla2 :: [Int] -> [Int] -> [Int] mezcla2 p@(x:xs) q@(y:ys) | x < y | x > y | otherwise mezcla2 [] ys mezcla2 xs [] = = = = = x:mezcla2 xs q y:mezcla2 p ys x:mezcla2 xs ys ys xs

104

Captulo 4. Aplicaciones de programacin funcional

Bibliografa
[1] H. C. Cunningham. Notes on functional programming with haskell. Technical report, University of Mississippi, 2007. [2] J. Fokker. Programacin funcional. Technical report, Universidad de Utrech, 1996. [3] B. C. Ruiz, F. Gutirrez, P. Guerrero, and J. Gallardo. Razonando con Haskell (Un curso sobre programacin funcional). Thompson, 2004. [4] S. Thompson. Haskell: The Craft of Functional Programming. AddisonWesley, second edition, 1999. En Bib. [5] E. P. Wentworth. Introduction to Funcional Programming. Technical report, Parallel Processing Group. Rhodes University, 1994.

105

ndice alfabtico
Camino, 80 Direccin, 91 Punto, 80 Racional, 81 Ratio, 91 &&&, 15 rbol, 87 =, 20 anterior_1, 15 anterior_2, 15 aplana, 90 arco_coseno_1, 39 arco_coseno_2, 40 arco_seno_1, 39 arco_seno_2, 40 carcterDeDgito, 65 combinaciones_1, 101 combinaciones_2, 101 comb, 9 compuesta, 34 concat_1, 44 concat_2, 44 concat_3, 44 conc, 43 cuadrado_1, 11 cuadrado_2, 11 cuadrado_3, 11 da, 36 dgitoDeCarcter, 64 deEnteroACadena_1, 68 deEnteroACadena_2, 69 derivadaBurda, 38 derivadaFinaDelSeno, 38 derivadaFina, 38 derivadaSuper, 38 derivada, 38 desde_1, 65 desde_2, 65 distancia_al_origen, 80 distancia, 80 divisible, 34 divisores_1, 35 divisores_2, 35 divisores, 35 doble_1, 21 doble_2, 21 doble_3, 21 dosElevadoA_1, 24 dosElevadoA_2, 24 dosElevadoA_3, 24 ejrbol_1, 87 elemrbol, 88 elem_ord, 90 esPositivo_1, 24 esPositivo_2, 25 esPositivo_3, 25 escribeRacional, 83 fact1, 8 fact2, 8 fact3, 8 fact4, 8 fact5, 8 fact6, 8 factoriales_1, 31 factoriales_2, 32 factoriales_3, 32
106

ndice alfabtico

107

factoriales_4, 32 factoriales_5, 32 factorial, 9 fib_1, 77 fib_2, 78 fib_3, 78 finales, 96 flip, 34 igualLista, 43 igual_conjunto_1, 57, 98 igual_conjunto_2, 57, 99 igual_conjunto_3, 57, 99 impar1, 10 impar2, 10 impar3, 10 impar4, 10 incmin_1, 79 iniciales, 95 insertarbol, 89 inserta, 58 inversa, 40 inverso_1, 23 inverso_2, 23 inverso_3, 23 listarbol, 89 lista_ordenada_1, 56 lista_ordenada_2, 56 lista_ordenada, 56 longitud_camino_1, 80 longitud_camino_2, 81 mezcla_1, 63 mezcla_2, 63 mezcla, 63 mitad_1, 22 mitad_2, 22 mitad_3, 22 mueve, 91 n_abs_1, 13 n_abs_2, 14 n_and_1, 28

n_and_2, 28 n_curry, 87 n_dropWhile, 50 n_drop, 49 n_elem_1, 53 n_elem_2, 53 n_elem_3, 53 n_elem_4, 53 n_elem_5, 54 n_elem_6, 54 n_filter_1, 26 n_filter_2, 26 n_foldl, 30 n_foldr, 30 n_fst3, 76 n_fst, 74 n_gcd_1, 83 n_gcd_2, 83 n_head, 45 n_id, 17 n_init_1, 47 n_init_2, 47 n_init_3, 47 n_iterate, 68 n_last_1, 45 n_last_2, 46 n_last_3, 46 n_last_4, 46 n_last_5, 46 n_length_1, 52 n_length_2, 52 n_length_3, 52 n_length_4, 52 n_lookup, 84 n_map_1, 25 n_map_2, 25 n_minimum_1, 61 n_minimum_2, 61 n_minimum_3, 61 n_notElem_1, 55

108

ndice alfabtico

n_notElem_2, 55 n_notElem_3, 55 n_notElem_4, 55 n_notElem_5, 55 n_notElem_6, 55 n_notElem_7, 54, 55 n_or_1, 29 n_or_2, 29 n_producto_1, 27 n_producto_2, 28 n_repeat_1, 66 n_repeat_2, 66 n_repeat_3, 66 n_replicate_1, 67 n_replicate_2, 67 n_replicate_3, 67 n_reverse_1, 51 n_reverse_2, 51 n_reverse_3, 51 n_scanr, 31 n_signum, 14 n_snd3, 76 n_snd, 75 n_splitAt, 77 n_sum_1, 27 n_sum_2, 27 n_tail, 45 n_take, 48 n_thd3, 76 n_uncurry, 87 n_until, 33 n_zipWith, 86 n_zip_1, 85 n_zip_2, 85 nth, 50 ordenaR, 74 ordena_por_insercin_1, 60 ordena_por_insercin_2, 60 ordena_por_insercin_3, 60 ordena_por_m, 64

ordenada_por_rbol, 90 permutaciones_1, 100 permutaciones_2, 100 posicin_1, 73 posicin_2, 73 potencia_1, 16 potencia_2, 16 primos_1, 36 primos_por_criba_1, 69 primos_por_criba_2, 70 primo, 35 puntoCero, 39 qDiv, 82 qMul, 82 qRes, 82 qSum, 82 rCero, 92 rCuarto, 92 rDiv, 92 rDos, 92 rMedio, 92 rMul, 92 rRes, 92 rSum, 92 rTercio, 92 rTres, 92 rUno, 92 raz_cbica_1, 39 raz_cbica_2, 40 raz_cuadrada_1, 39 raz_cuadrada_2, 40 raices_1, 13 raices_2, 13 raizCuadrada, 39 reinas, 102 segmentos, 97 siguiente_1, 20 siguiente_2, 20 simplificarRatio, 91 simplificar, 82

ndice alfabtico

109

subconjunto_1, 98 subconjunto_2, 98 sublistas, 97 suma_de_cuadrados_1, 12 suma_de_cuadrados_2, 12 suma_de_cuadrados_3, 12 suma_de_cuadrados_4, 12 tamao, 88 todosImpares_1, 71 todosImpares_2, 72 todosImpares_3, 72 todosPares_1, 71 todosPares_2, 71 todosPares_3, 71 tringulo, 72 variable, 77

También podría gustarte