-- I1M 2009-10: G1_Rel_9.hs
-- 9ª relación de ejercicios (3 de Diciembre)
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================

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

import Data.Char
import Data.List
import Test.QuickCheck

-- ----------------------------------------------------------------------------
-- Ejercicio 1. La función 
--    divideMedia :: [Double] -> ([Double],[Double])
-- dada una lista numérica, xs, calcula la lista [ys,zs], donde ys contiene los
-- elementos de xs estrictamente menores que la media, mientras que zs contiene
-- los elementos de xs estrictamente mayores que la media. Por ejemplo, 
--    divideMedia [6,7,2,8,6,3,4]  ==>  [[2.0,3.0,4.0],[6.0,7.0,8.0,6.0]]
--    divideMedia [1,2,3]          ==>  [[1.0],[3.0]]
-- Definir la función divideMedia por filtrado, comprensión y recursión.
-- ----------------------------------------------------------------------------

-- La definición por filtrado es
divideMediaF :: [Double] -> ([Double],[Double])
divideMediaF xs = undefined

-- (media xs) es la media de xs. Por ejemplo,
--    media [1,2,3]       ==>  2.0
--    media [1,-2,3.5,4]  ==>  1.625 
media :: [Double] -> Double
media xs = (sum xs) / fromIntegral (length xs)

-- La definición por comprensión es
divideMediaC :: [Double] -> ([Double],[Double])
divideMediaC xs = undefined

-- La definición por recursión es
divideMediaR :: [Double] -> ([Double],[Double])
divideMediaR xs = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 2. Comprobar con QuickCheck que las tres definiciones
-- anteriores divideMediaF, divideMediaC y divideMediaR son
-- equivalentes.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_divideMedia :: [Double] -> Bool
prop_divideMedia xs = undefined
    
-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 3. Comprobar con QuickCheck que si (ys,zs) es el par
-- obtenido aplicándole la función divideMediaF a xs, entonces la suma
-- de las longitudes de ys y zs es menor o igual que la longitud de xs.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_longitudDivideMedia :: [Double] -> Bool
prop_longitudDivideMedia xs = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 4. Comprobar con QuickCheck que si (ys,zs) es el par
-- obtenido aplicándole la función divideMediaF a xs, entonces todos los
-- elementos de ys son menores que todos los elementos de zs.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_divideMediaMenores :: [Double] -> Bool
prop_divideMediaMenores xs = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 5. Comprobar con QuickCheck que si (ys,zs) es el par
-- obtenido aplicándole la función divideMediaF a xs, entonces todos la
-- media de xs no pertenece a ys ni a zs.
-- Nota: Usar la función notElem tal que (notElem x ys) se verifica si y
-- no pertenece a ys.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_divideMediaSinMedia :: [Double] -> Bool
prop_divideMediaSinMedia xs = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 6. Se considera la función 
--    filtraAplica :: (a -> b) -> (a -> Bool) -> [a] -> [b]
-- tal que (filtraAplica f p xs) es la lista obtenida aplicándole a los
-- elementos de xs que cumplen el predicado p la función f. Por ejemplo,
--    filtraAplica (4+) (<3) [1..7]  =>  [5,6]
-- Se pide, definir la función
-- 1. por comprensión,
-- 2. usando map y filter,
-- 3. por recursión y
-- 4. por plegado (con foldr).
-- ---------------------------------------------------------------------

-- La definición por comprensión es
filtraAplica_1 :: (a -> b) -> (a -> Bool) -> [a] -> [b]
filtraAplica_1 f p xs = undefined

-- La definición con map y filter es
filtraAplica_2 :: (a -> b) -> (a -> Bool) -> [a] -> [b]
filtraAplica_2 f p xs = undefined

-- La definición por recursión es
filtraAplica_3 :: (a -> b) -> (a -> Bool) -> [a] -> [b]
filtraAplica_3 = undefined

-- La definición por plegado es
filtraAplica_4 :: (a -> b) -> (a -> Bool) -> [a] -> [b]
filtraAplica_4 f p = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 7. Redefinir por recursión la función
--    takeWhile :: (a -> Bool) -> [a] -> [a]
-- tal que (takeWhile p xs) es la lista de los elemento de xs hasta el
-- primero que no cumple la propiedad p. Por ejemplo,
--    takeWhile (<7) [2,3,9,4,5]  =>  [2,3]
-- ---------------------------------------------------------------------

-- La definición es
takeWhile' :: (a -> Bool) -> [a] -> [a]
takeWhile' = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 8. Redefinir por recursión la función
--    dropWhile :: (a -> Bool) -> [a] -> [a]
-- tal que (dropWhile p xs) es la lista de eliminando los elemento de xs
-- hasta el primero que cumple la propiedad p. Por ejemplo,
--    dropWhile (<7) [2,3,9,4,5]  =>  [9,4,5]
-- ---------------------------------------------------------------------

-- La definición es
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 9. Redefinir, usando foldr, la función concat. Por ejemplo, 
--    concat' [[1,3],[2,4,6],[1,9]]  =>  [1,3,2,4,6,1,9]
-- ---------------------------------------------------------------------

-- La definición es
concat' :: [[a]] -> [a]
concat' = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 10. Redefinir, usando foldr, la función map. Por ejemplo,
--    map' (+2) [1,7,3]  =>  [3,9,5]
-- ---------------------------------------------------------------------

-- La definición es
map' :: (a -> b) -> [a] -> [b]
map' f = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 11. Redefinir, usando foldr, la función filter. Por
-- ejemplo, 
--    filter' (<4) [1,7,3,2]  =>  [1,3,2]
-- ---------------------------------------------------------------------

-- La definición es
filter' :: (a -> Bool) -> [a] -> [a]
filter' p = undefined
