-- I1M 2009-10: G1_Rel_5.hs
-- 5ª relación de ejercicios (4 de Noviembre)
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================

-- ---------------------------------------------------------------------
-- Importación de librerías auxiliares                                --
-- ---------------------------------------------------------------------

import Test.QuickCheck

-- ---------------------------------------------------------------------
-- Ejercicio 1. Usando una lista por comprensión, definir la constante
-- sumaDeCuadrados cuyo valor sea la suma 1^2 + 2^2 + ... 100^2 y
-- calcular su valor.
-- ---------------------------------------------------------------------

-- La defición es
sumaDeCuadrados = undefined

-- Su evaluación es

-- ---------------------------------------------------------------------
-- Ejercicio 2.1. Redefinir por comprensión la función
--    replicate :: Int -> a -> [a]
-- tal que (replicate n x) es la lista formada por n copias del elemento
-- x. Por ejemplo,
--    *Main> replicate 3 True
--    [True, True, True]
-- Llamar la nueva definición replicate'.
-- ---------------------------------------------------------------------

-- La definición
replicate' :: Int -> a -> [a]
replicate' n x = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 2.2, Comprobar con QuickCheck que para todo número entero
-- positivo n (menor que 100) y todo elemento x, se tiene que la longitud de 
-- (replicate n x) es n. 
-- ---------------------------------------------------------------------

-- La propiedad es
prop_replicate :: Int -> Int -> Bool
prop_replicate n x = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.1. Una terna (x,y,z) de enteros positivos es pitagórica si 
-- x^2 + y^2 = z^2. Usando una lista por comprensión, definir la función
--    pitagoricas :: Int -> [(Int, Int, Int)]
-- tal que (pitagoricas n) es la lista de todas las ternas pitagóricas
-- cuyas componentes están entre 1 y n. Por ejemplo, 
--    *Main> pitagoricas 10 
--    [(3,4,5),(4,3,5),(6,8,10),(8,6,10)]
-- ---------------------------------------------------------------------

pitagoricas :: Int -> [(Int, Int, Int)]
pitagoricas n = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.2. Definir la función 
--    numeroDePares :: (Int,Int,Int) -> Int
-- tal que (numeroDePares t) es el número de elementos pares de la terna
-- t. Por ejemplo,
--    numeroDePares (3,5,7)  =>  0
--    numeroDePares (3,6,7)  =>  1
--    numeroDePares (3,6,4)  =>  2
--    numeroDePares (4,6,4)  =>  3
-- ---------------------------------------------------------------------

numeroDePares :: (Int,Int,Int) -> Int
numeroDePares (x,y,z) = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.3. Definir la función
--    conjetura :: Int -> Bool
-- tal que (conjetura n) se verifica si todas las ternas pitagóricas
-- cuyas componentes están entre 1 y n tiene un número impar de números
-- pares. Por ejemplo,
--    conjetura 10  =>  True
-- ---------------------------------------------------------------------

conjetura :: Int -> Bool
conjetura n = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3.4. Demostrar la conjetura para todas las ternas
-- pitagóricas. 
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 4. Un entero positivo es perfecto si es igual a la suma de
-- sus factores, excluyendo el propio número. Usando una lista por
-- comprensión y la función factores (del tema), definir la función 
--    perfectos :: Int -> [Int]
-- tal que (perfectos n) es la lista de todos los números perfectos
-- menores que n. Por ejemplo: 
--    *Main> perfectos 500
--    [6,28,496]
-- ---------------------------------------------------------------------

-- La función factores del tema es
factores :: Int -> [Int]
factores n = undefined

-- La definición es
perfectos :: Int -> [Int]
perfectos n = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 5. La función 
--    pares :: [a] -> [b] -> [(a,b)]
-- definida por
--    pares xs ys = [(x,y) | x <- xs, y <- ys]
-- toma como argumento dos listas y devuelve la listas de los pares con
-- el primer elemento de la primera lista y el segundo de la
-- segunda. Por ejemplo,
--    *Main> pares [1..3] [4..6]
--    [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]
-- 
-- Demostrar cómo la función pares puede redefinirse usando dos
-- listas por comprensión con un generador cada una. Comprobar con
-- QuickCheck que las dos definiciones son equivalentes.
-- 
-- Indicación: Utilizar la función predefinida concat y encajar una
-- lista por comprensión dentro de la otra. 
-- ---------------------------------------------------------------------

-- La definición de pares es
pares :: [a] -> [b] -> [(a,b)]
pares xs ys = [(x,y) | x <- xs, y <- ys]

-- La redefinición de pares es
pares' :: [a] -> [b] -> [(a,b)]
pares' xs ys = undefined

-- La propiedad es
prop_pares :: (Eq a, Eq b) => [a] -> [b] -> Bool
prop_pares xs ys = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 6. En el tema 5 se ha definido la función 
--    posiciones :: Eq a => a -> [a] -> [Int]
-- tal que (posiciones x xs) es la lista de las posiciones ocupadas por
-- el elemento x en la lista xs. Por ejemplo,
--    posiciones 5 [1,5,3,5,5,7]  =>  [1,3,4]
-- 
-- Redefinir la función posiciones usando la función busca (definida en
-- el tema). Llamar a la nueva función posiciones'. Comprobar con
-- QuickCheck que posiciones' es equivalente a posiciones.
-- ---------------------------------------------------------------------

-- La definición de posiciones es
posiciones :: Eq a => a -> [a] -> [Int]
posiciones x xs = [i | (x',i) <- zip xs [0..], x == x']

-- La definición de busca es
busca :: Eq a => a -> [(a, b)] -> [b]
busca c t = [v | (c', v) <- t, c' == c]

-- La redefinición de posiciones es
posiciones' :: Eq a => a -> [a] -> [Int]
posiciones' x xs = undefined

-- La propiedad de equivalencia es
prop_posiciones :: Eq a => a -> [a] -> Bool
prop_posiciones x xs = undefined

-- La comprobación es 

-- ---------------------------------------------------------------------
-- Ejercicio 7. El producto escalar de dos listas de enteros xs y ys de
-- longitud n viene dado por la suma de los productos de los elementos
-- correspondientes. Definir por comprensión la función 
--    productoEscalar :: [Int] -> [Int] -> Int
-- tal que (productoEscalar xs ys) es el producto escalar de las listas
-- xs e ys. Por ejemplo,
--    productoEscalar [1,2,3] [4,5,6]  =>  32
--
-- Usar QuickCheck para comprobar la propiedad conmutativa del producto
-- escalar.  
-- ---------------------------------------------------------------------

-- La definición es
productoEscalar :: [Int] -> [Int] -> Int
productoEscalar xs ys = undefined

-- La propiedad conmutativa es
prop_conmutativa_productoEscalar xs ys = undefined

-- La comprobación es 

-- ---------------------------------------------------------------------
-- Ejercicio 8. Modificar el programa de cifrado César para que pueda
-- utilizar también letras mayúsculas. Por ejemplo,
--    *Main> descifra "Ytit Ufwf Sfif"
--    "Todo Para Nada"
-- ---------------------------------------------------------------------

-- (minuscula2int c) es el entero correspondiente a la letra minúscula
-- c. Por ejemplo, 
--    minuscula2int 'a'  =>  0
--    minuscula2int 'd'  =>  3
--    minuscula2int 'z'  =>  25
minuscula2int :: Char -> Int
minuscula2int c = undefined

-- (mayuscula2int c) es el entero correspondiente a la letra mayúscula
-- c. Por ejemplo, 
--    mayuscula2int 'A'  =>  0
--    mayuscula2int 'D'  =>  3
--    mayuscula2int 'Z'  =>  25
mayuscula2int :: Char -> Int
mayuscula2int c = undefined

-- (int2minuscula n) es la letra minúscula correspondiente al entero
-- n. Por ejemplo, 
--    int2minuscula 0   =>  'a'
--    int2minuscula 3   =>  'd'
--    int2minuscula 25  =>  'z'
int2minuscula :: Int -> Char
int2minuscula n = undefined

-- (int2mayuscula n) es la letra minúscula correspondiente al entero
-- n. Por ejemplo, 
--    int2mayuscula 0   =>  'A'
--    int2mayuscula 3   =>  'D'
--    int2mayuscula 25  =>  'Z'
int2mayuscula :: Int -> Char
int2mayuscula n = undefined

-- (desplaza n c) es el carácter obtenido desplazando n caracteres el
-- carácter c. Por ejemplo, 
--    desplaza   3  'a'  =>  'd'
--    desplaza   3  'y'  =>  'b'
--    desplaza (-3) 'd'  =>  'a'
--    desplaza (-3) 'b'  =>  'y'
--    desplaza   3  'A'  =>  'D'
--    desplaza   3  'Y'  =>  'B'
--    desplaza (-3) 'D'  =>  'A'
--    desplaza (-3) 'B'  =>  'Y'
desplaza :: Int -> Char -> Char
desplaza n c = undefined

-- (codifica n xs) es el resultado de codificar el texto xs con un
-- desplazamiento n. Por ejemplo, 
--    *Main> codifica   3  "En Todo La Medida" 
--    "Hq Wrgr Od Phglgd"
--    *Main> codifica (-3) "Hq Wrgr Od Phglgd"
--    "En Todo La Medida"
codifica :: Int -> String -> String
codifica n xs = undefined

-- tabla es la lista de la frecuencias de las letras en castellano, Por
-- ejemplo, la frecuencia de la 'a' es del 12.53%, la de la 'b' es
-- 1.42%. 
tabla :: [Float]
tabla = [12.53, 1.42, 4.68, 5.86, 13.68, 0.69, 1.01, 
          0.70, 6.25, 0.44, 0.01,  4.97, 3.15, 6.71, 
          8.68, 2.51, 0.88, 6.87,  7.98, 4.63, 3.93, 
          0.90, 0.02, 0.22, 0.90,  0.52]

-- (porcentaje n m) es el porcentaje de n sobre m. Por ejemplo,
--    porcentaje 2 5  =>  40.0  
porcentaje :: Int -> Int -> Float
porcentaje n m = undefined

-- (letras xs) es la cadena formada por las letras de la cadena xs. Por
-- ejemplo,  
--    letras "Esto Es Una Prueba"  =>  "EstoEsUnaPrueba"
letras :: String -> String
letras xs = undefined

-- (ocurrencias x xs) es el número de veces que ocurre el carácter x en
-- la cadena xs. Por ejemplo, 
--    ocurrencias 'a' "Salamanca"  =>  4  
ocurrencias :: Char -> String -> Int
ocurrencias x xs = undefined

-- (frecuencias xs) es la frecuencia de cada una de las letras de la
-- cadena xs. Por ejemplo, 
--    *Main> frecuencias "En Todo La Medida"
--    [14.3,0,0,21.4,14.3,0,0,0,7.1,0,0,7.1,
--     7.1,7.1,14.3,0,0,0,0,7.1,0,0,0,0,0,0]
frecuencias :: String -> [Float]
frecuencias xs = undefined

-- (chiCuad os es) es la medida chi cuadrado de las distribuciones os y
-- es. Por ejemplo, 
--    chiCuad [3,5,6] [3,5,6]  =>  0.0
--    chiCuad [3,5,6] [5,6,3]  =>  3.9666667
chiCuad :: [Float] -> [Float] -> Float
chiCuad os es = undefined

-- (rota n xs) es la lista obtenida rotando n posiciones los elementos
-- de la lista xs. Por ejemplo, 
--    rota 2 "manolo"  =>  "noloma"  
rota :: Int -> [a] -> [a]
rota n xs = undefined

-- (descifra xs) es la cadena obtenida descodificando la cadena xs por
-- el anti-desplazamiento que produce una distribución de letras con la
-- menor deviación chi cuadrado respecto de la tabla de distribución de
-- las letras en castellano. Por ejemplo, 
--    *Main> codifica 5 "Todo Para Nada"
--    "Ytit Ufwf Sfif"
--    *Main> descifra "Ytit Ufwf Sfif"
--    "Todo Para Nada"
descifra :: String -> String
descifra xs = undefined
