Acciones

Relación 7

De Informática de 1º de Matemáticas [Curso 2021-22, Grupo 2]

-- I1M 2021-22: Rel_7.hs 
-- Definiciones por recursión y por comprensión 
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================

-- ---------------------------------------------------------------------
-- Introducción                                                       --
-- ---------------------------------------------------------------------

-- Esta relación es de repaso y servirá para seguir practicando los
-- conceptos de recursión y comprensión
-- En esta relación se presentan ejercicios con dos definiciones (una
-- por recursión y otra por comprensión) y la comprobación de la
-- equivalencia de las dos definiciones con QuickCheck. Los ejercicios
-- corresponden a los temas 5 y 6 
-- ---------------------------------------------------------------------
-- Importación de librerías auxiliares                                --
-- ---------------------------------------------------------------------

import Test.QuickCheck
import Data.List

-- ---------------------------------------------------------------------
-- Operaciones conjuntistas sobre listas.
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 1.1. Definir, por comprensión, la función
--    subconjunto :: Eq a => [a] -> [a] -> Bool
-- tal que (subconjunto xs ys) se verifica si xs es un subconjunto de
-- ys; es decir, si todos los elementos de xs pertenecen a ys. Por
-- ejemplo, 
--    subconjunto [3,2,3] [2,5,3,5]  ==  True
--    subconjunto [3,2,3] [2,5,6,5]  ==  False
-- ---------------------------------------------------------------------
-- Lucía Hernández, Lucía González , Adolfo Sagrera, Elsa Domínguez, Ana Sosa Caballero
subconjunto :: Eq a => [a] -> [a] -> Bool
subconjunto xs ys = and [elem x ys | x<- xs]

-- Sara Cerro
subconjunto :: Eq a => [a] -> [a] -> Bool
subconjunto xs ys = length [ x | x <- xs, elem x ys] == length xs

-- ---------------------------------------------------------------------
-- Ejercicio 1.2. Definir, por recursión, la función
--    subconjuntoR :: Eq a => [a] -> [a] -> Bool
-- tal que (subconjuntoR xs ys) se verifica si xs es un subconjunto de
-- ys; es decir, si todos los elementos de xs pertenecen a ys. Por
-- ejemplo, 
--    subconjuntoR [3,2,3] [2,5,3,5]  ==  True
--    subconjuntoR [3,2,3] [2,5,6,5]  ==  False
-- ---------------------------------------------------------------------
-- Lucía Hernández, Adolfo Sagrera Vivancos, Lucía González Guillén
subconjuntoR :: Eq a => [a] -> [a] -> Bool
subconjuntoR [] _ = True
subconjuntoR (x:xs) ys | elem x ys = subconjuntoR xs ys
                       | otherwise = False
-- Elsa Domínguez
subconjuntoR' :: Eq a => [a] -> [a] -> Bool
subconjuntoR' [] _ = True
subconjuntoR' (x:xs) ys = x `elem` ys && (subconjuntoR xs ys)

-- Ana Sosa Caballero
subconjuntoR :: Eq a => [a] -> [a] -> Bool
subconjuntoR _ [] = False
subconjuntoR [] _ = True
subconjuntoR (x:xs) ys = and [elem x ys && subconjuntoR xs ys]

-- ---------------------------------------------------------------------
-- Ejercicio 1.3. Comprobar con QuickCheck que las definiciones
-- subconjunto y subconjuntoR son equivalentes.
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero, Lucía González
-- La propiedad es
prop_subconjuntoR :: [Int] -> [Int] -> Bool
prop_subconjuntoR xs ys = (subconjunto xs ys) == (subconjuntoR xs ys)

-- La comprobación es quickCheck prop_subconjuntoR
-- +++ OK, passed 100 tests

-- ---------------------------------------------------------------------
-- Ejercicio 1.4. Definir, mediante all, la función 
--    subconjuntoA :: Eq a => [a] -> [a] -> Bool
-- tal que (subconjuntoA xs ys) se verifica si xs es un subconjunto de
-- ys. Por ejemplo,
--    subconjuntoA [1,3,2,3] [1,2,3]  ==  True
--    subconjuntoA [1,3,4,3] [1,2,3]  ==  False
-- ---------------------------------------------------------------------
 ---Lucía González
subconjuntoA :: Eq a => [a] -> [a] -> Bool
subconjuntoA xs ys = all (subconjunto ys)[xs]
 
-- ---------------------------------------------------------------------
-- Ejercicio 1.5. Comprobar con QuickCheck que las funciones subconjunto
-- y subconjuntoA son equivalentes.
-- ---------------------------------------------------------------------
 
-- La propiedad es
prop_subconjuntoA :: [Int] -> [Int] -> Bool
prop_subconjuntoA = undefined
 
-- La comprobación es
 
-- ---------------------------------------------------------------------
-- Ejercicio 2. Definir la función
--    iguales :: Eq a => [a] -> [a] -> Bool
-- tal que (iguales xs ys) se verifica si xs e ys son iguales; es decir,
-- tienen los mismos elementos. Por ejemplo, 
--    iguales [3,2,3] [2,3]    ==  True
--    iguales [3,2,3] [2,3,2]  ==  True
--    iguales [3,2,3] [2,3,4]  ==  False
--    iguales [2,3] [4,5]      ==  False
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez
iguales :: Eq a => [a] -> [a] -> Bool
iguales xs ys = subconjuntoR xs ys && subconjuntoR ys xs
-- Adolfo Sagrera Vivancos, Lucía González, Ana Sosa Caballero
iguales1 :: Eq a => [a] -> [a] -> Bool
iguales1 xs ys = and [ elem x ys && elem y xs | x <- xs, y <- ys]

-- ---------------------------------------------------------------------
-- Ejercicio 3.1. Definir, por comprensión, la función
--    union :: Eq a => [a] -> [a] -> [a]
-- tal que (union xs ys) es la unión de los conjuntos xs e ys. Por
-- ejemplo, 
--    union [3,2,5] [5,7,3,4]  ==  [3,2,5,7,4]
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
union1 :: Eq a => [a] -> [a] -> [a]
union1 xs ys = [x | x<- nub(xs++ys)]
-- Elsa Domínguez
union' :: Eq a => [a] -> [a] -> [a]
union' xs ys = [x | x <- xs, x `notElem` ys] ++ ys 

-- ---------------------------------------------------------------------
-- Ejercicio 3.2. Definir, por recursión, la función
--    unionR :: Eq a => [a] -> [a] -> [a]
-- tal que (unionR xs ys) es la unión de los conjuntos xs e ys. Por
-- ejemplo, 
--    unionR [3,2,5] [5,7,3,4]  ==  [2,5,7,3,4]
-- ---------------------------------------------------------------------
-- Lucía Hernández
unionR :: Eq a => [a] -> [a] -> [a]
unionR [] xs = nub xs
unionR xs [] = nub xs
unionR (x:xs) ys | not(elem x ys) = x: unionR xs ys
                 | otherwise = unionR xs ys
-- Elsa Domínguez
unionR1 :: Eq a => [a] -> [a] -> [a]
unionR1 xs ys = nub (unionR' xs ys)
unionR' [] ys = ys
unionR' (x:xs) (ys) = unionR xs (x:ys)

-- Ana Sosa Caballero
unionR :: Eq a => [a] -> [a] -> [a]
unionR xs [] = xs
unionR [] ys = ys
unionR xs (y:ys) = nub( xs ++ [y] ++ unionR [] ys)


-- ---------------------------------------------------------------------
-- Ejercicio 3.3. Comprobar con QuickCheck que union y unionR son
-- equivalentes. 
-- ---------------------------------------------------------------------
-- Lucía Hernández
-- La propiedad es
prop_union :: [Int] -> [Int] -> Bool
prop_union xs ys  = (union1 xs ys == unionR xs ys) ||
                    (iguales (union1 xs ys) (unionR xs ys))
-- Elsa Domínguez
-- La propiedad es
prop_union :: [Int] -> [Int] -> Bool
prop_union xs ys = iguales (union' xs ys) (unionR xs ys)
-- La comprobación es quickCheck prop_union
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 4. Comprobar con QuickCheck que la unión es conmutativa.
-- ---------------------------------------------------------------------
-- Lucía Hernández
-- La propiedad es
prop_union_conmutativa :: [Int] -> [Int] -> Bool
prop_union_conmutativa xs ys =(union1 xs ys == union1 ys xs) ||
                    (iguales (union1 xs ys) (union1 ys xs))

-- Elsa Domínguez, Ana Sosa Caballero
-- La propiedad es
prop_union_conmutativa :: [Int] -> [Int] -> Bool
prop_union_conmutativa xs ys = iguales (union' xs ys) (union' ys xs)
-- La comprobación es quickCheck prop_union_conmutativa
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 5.1. Definir, por comprensión, la función
--    interseccion :: Eq a => [a] -> [a] -> [a]
-- tal que (interseccion xs ys) es la intersección de xs e ys. Por
-- ejemplo, 
--    interseccion [3,2,5] [5,7,3,4]  ==  [3,5]
--    interseccion [3,2,5] [9,7,6,4]  ==  []
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero
interseccion :: Eq a => [a] -> [a] -> [a]
interseccion xs ys  = [ x | x<- xs, elem x ys]

-- ---------------------------------------------------------------------
-- Ejercicio 5.2. Definir, por recursión, la función
--    interseccionR :: Eq a => [a] -> [a] -> [a]
-- tal que (interseccionR xs ys) es la intersección de xs e ys. Por
-- ejemplo, 
--    interseccionR [3,2,5] [5,7,3,4]  ==  [3,5]
--    interseccionR [3,2,5] [9,7,6,4]  ==  []
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
interseccionR :: Eq a => [a] -> [a] -> [a]
interseccionR [] _ = []
interseccionR _ [] = []
interseccionR (x:xs) ys | elem x ys = x : interseccionR xs ys
                        | otherwise = interseccionR xs ys
-- Elsa Domínguez
interseccionR' :: Eq a => [a] -> [a] -> [a]
interseccionR' [] _ = []
interseccionR' (x:xs) ys | x `elem` ys = x:interseccionR xs ys
                        | otherwise = interseccionR xs ys

-- ---------------------------------------------------------------------
-- Ejercicio 5.3. Comprobar con QuickCheck que interseccion e
-- interseccionR son equivalentes.
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero
-- La propiedad es
prop_interseccion :: [Int] -> [Int] -> Bool
prop_interseccion xs ys = interseccion xs ys == interseccionR xs ys

-- La comprobación es quickCheck prop_interseccion
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 6. Comprobar con QuickCheck si se cumple la siguiente
-- propiedad 
--    A ∪ (B ∩ C) = (A ∪ B) ∩ C
-- donde se considera la igualdad como conjuntos. En el caso de que no
-- se cumpla verificar el contraejemplo calculado por QuickCheck.
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
prop_union_interseccion :: [Int] -> [Int] -> [Int] -> Bool
prop_union_interseccion xs ys zs = union1 xs (interseccion ys zs) == interseccion (union xs ys) zs

-- La comprobación es 

-- Elsa Domínguez
prop_union_interseccion :: [Int] -> [Int] -> [Int] -> Bool
prop_union_interseccion a b c = union' a (interseccion b c) == interseccion (union' a b) c

-- La comprobación es quickCheck prop_union_interseccion
-- *** Failed! Falsifiable (after 3 tests and 3 shrinks):
-- [0]
-- []
-- []
-- λ> union' [0] (interseccion [] [])
-- [0]
-- λ> interseccion (union' [0] []) []
-- []
-- ---------------------------------------------------------------------
-- Ejercicio 7.1. Definir, por comprensión, la función
--    diferencia :: Eq a => [a] -> [a] -> [a]
-- tal que (diferencia xs ys) es la diferencia entre los conjuntos xs e
-- ys; es decir, la lista de los elementos que sólo pertenecen a xs. Por
-- ejemplo,  
--    diferencia [3,2,5,6] [5,7,3,4]  ==  [2,6]
--    diferencia [3,2,5] [5,7,3,2]    ==  []
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero
diferencia :: Eq a => [a] -> [a] -> [a]
diferencia xs ys = [x | x<-xs, not(elem x ys)] 

-- ---------------------------------------------------------------------
-- Ejercicio 7.2. Definir, por recursión, la función
--    diferenciaR :: Eq a => [a] -> [a] -> [a]
-- tal que (diferenciaR xs ys) es la diferencia entre los conjuntos xs e
-- ys; es decir, la lista de los elementos que sólo pertenecen a xs. Por
-- ejemplo,  
--    diferenciaR [3,2,5,6] [5,7,3,4]  ==  [2,6]
--    diferenciaR [3,2,5] [5,7,3,2]    ==  []
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero
diferenciaR :: Eq a => [a] -> [a] -> [a]
diferenciaR xs [] = xs
diferenciaR [] _ = []
diferenciaR (x:xs) ys | not(elem x ys) = x: diferenciaR xs ys
                      | otherwise = diferenciaR xs ys

-- ---------------------------------------------------------------------
-- Ejercicio 7.3. Comprobar con QuickCheck que diferencia y diferenciaR 
-- son equivalentes.
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero
-- La propiedad es
prop_diferencia :: [Int] -> [Int] -> Bool
prop_diferencia xs ys = diferenciaR xs ys == diferencia xs ys

-- La comprobación es quickCheck prop_diferencia
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 8. Comprobar con QuickCheck si la diferencia es
-- conmutativa. 
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sosa Caballero
prop_diferencia_conmutativa :: [Int] -> [Int] -> Bool
prop_diferencia_conmutativa xs ys = diferenciaR xs ys == diferenciaR ys xs

-- La comprobación es quickCheck prop_diferencia_conmutativa
-- *** Failed! Falsifiable (after 2 tests and 1 shrink):
-- []
-- [0]

-- ---------------------------------------------------------------------
-- Ejercicio 9. Comprobar con QuickCheck si se cumple la siguiente
-- propiedad: A \ B ⊂ A
-- ---------------------------------------------------------------------
-- Elsa Domínguez, Ana Sosa Caballero
-- La propiedad es
prop_diferencia_subconjunto :: [Int] -> [Int] -> Bool
prop_diferencia_subconjunto a b = subconjunto (diferencia a b) a

-- La comprobación es quickCheck prop_diferencia_subconjunto
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 10. Comprobar con QuickCheck si se cumple la siguiente
-- propiedad: (A \ B) ∩ B = ∅.
-- ---------------------------------------------------------------------
-- Elsa Domínguez, Ana Sosa Caballero 
-- La propiedad es
prop_diferencia_interseccion :: [Int] -> [Int] -> Bool
prop_diferencia_interseccion a b = interseccion (diferencia a b) b == []
                
-- La comprobación es quickCheck prop_diferencia_interseccion
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 11.1. Definir, por comprensión, la función
--    producto :: Eq a => [a] -> [a] -> [(a,a)]
-- tal que (producto xs ys) es el producto cartesiano de xs e ys. Por
-- ejemplo, 
--   producto [1,3] [2,4] == [(1,2),(1,4),(3,2),(3,4)]
-- ---------------------------------------------------------------------
-- Lucía Hernández
producto :: Eq a => [a] -> [a] -> [(a,a)]
producto xs ys = [(a,b) | (a,b) <- zip xs ys ++ zip xs ys']
                where ys' = reverse ys
-- Elsa Domínguez, Ana Sosa Caballero
producto' :: Eq a => [a] -> [a] -> [(a,a)]
producto' xs ys= [(x,y) | x <- xs, y <- ys]

-- ---------------------------------------------------------------------
-- Ejercicio 11.2. Definir, por recursión, la función
--    productoR :: Eq a => [a] -> [a] -> [(a,a)]
-- tal que (productoR xs ys) es el producto cartesiano de xs e ys. Por
-- ejemplo, 
--   productoR [1,3] [2,4] == [(1,2),(1,4),(3,2),(3,4)]
-- ---------------------------------------------------------------------
-- Lucía Hernández
productoR :: Eq a => [a] -> [a] -> [(a,a)]
productoR [] _ = []
productoR _ [] = []
productoR (x:xs) (y:ys) = (x,y): productoR xs (y:ys)
--Adriana Gordillo 
productoR :: Eq a => [a] -> [a] -> [(a,a)]
productoR _ [] = []
productoR [] _ = []
productoR (x:xs) ys = zip (take (length ys) (repeat x) ) ys ++ productoR xs ys
--Fernando Ruiz Mazo, Ana Sosa Caballero
productoR'' :: Eq a => [a] -> [a] -> [(a,a)]
productoR'' [] ys = []
productoR'' xs [] = []
productoR'' (x:xs) ys = [ (x,b) | b <- ys ] ++ productoR xs ys
--José Manuel García 
productoR :: Eq a => [a] -> [a] -> [(a,a)]
productoR1 _ [] = []
productoR1 (x:xs) (y:ys) = [(x,y)] ++ productoR1 (x:xs) ys
productoR [] _ = []
productoR (x:xs) (y:ys) = (productoR1 (x:xs) (y:ys) ) ++ (productoR xs (y:ys))
-- Elsa Domínguez 
productoR2 :: Eq a => [a] -> [a] -> [(a,a)]
productoR2 xs ys = nub (productoR2' xs ys)
productoR2' _ [] = []
productoR2' [] _ = []
productoR2' (x:xs) (y:ys) = (x,y):producto (x:xs) ys ++ (producto xs (y:ys))
-- ---------------------------------------------------------------------
-- Ejercicio 11.3. Comprobar con QuickCheck que producto y productoR 
-- son equivalentes.
-- ---------------------------------------------------------------------
-- Elsa Domínguez, Ana Sosa Caballero
-- La propiedad es
prop_producto :: [Int] -> [Int] -> Bool
prop_producto xs ys = iguales (producto xs ys) (productoR xs ys)

-- La comprobación es quickCheck prop_producto
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 12. Comprobar con QuickCheck que el número de elementos
-- de (producto xs ys) es el producto del número de elementos de xs y de
-- ys. 
-- ---------------------------------------------------------------------
-- Elsa Domínguez, Ana Sosa Caballero
-- La propiedad es
prop_elementos_producto :: [Int] -> [Int] -> Bool
prop_elementos_producto xs ys = length (producto xs ys) == length xs * length ys

-- La comprobación es quickCheck prop_elementos_producto
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicio 13. Definir la función 
--    subconjuntos :: [a] -> [[a]]
-- tal que (subconjuntos xs) es la lista de las subconjuntos de la lista
-- xs. Por ejemplo, 
--    ghci> subconjuntos [2,3,4]
--    [[2,3,4],[2,3],[2,4],[2],[3,4],[3],[4],[]]
--    ghci> subconjuntos [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], []]
-- ---------------------------------------------------------------------
-- Adriana Gordillo
subconjuntos :: [a] -> [[a]]
subconjuntos = subconjuntos xs = [take k cs | cs<-css, k<-[1..length xs-1]]++[xs,[]]
 where css= [ (drop n xs) ++ (take n xs) |n<-[0..length xs -1]]
--Fernando Ruiz Mazo, Elsa Domínguez
subconjuntosR :: [a] -> [[a]]
subconjuntosR [] = [[]]
subconjuntosR (x:xs) = [ x : ys | ys <- subconjuntos xs ] ++ subconjuntos xs

-- ---------------------------------------------------------------------
-- Ejercicio 14. Comprobar con QuickChek que el número de elementos de
-- (subconjuntos xs) es 2 elevado al número de elementos de xs.
--
-- Nota. Al hacer la comprobación limitar el tamaño de las pruebas como
-- se indica a continuación
--    quickCheckWith (stdArgs {maxSize=7}) prop_subconjuntos
-- ---------------------------------------------------------------------
-- Elsa Domínguez
-- La propiedad es
prop_subconjuntos :: [Int] -> Bool
prop_subconjuntos xs = length (subconjuntos xs) == 2^(length xs)

-- La comprobación es quickCheckWith (stdArgs {maxSize=7}) prop_subconjuntos
-- +++ OK, passed 100 tests.

-- ---------------------------------------------------------------------
-- Ejercicios variados
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 15.1 Se quiere formar una escalera con bloques cuadrados,
-- de forma que tenga un número determinado de escalones. Por ejemplo,
-- una escalera con tres escalones tendría la siguiente forma:
--        XX
--      XXXX
--    XXXXXX
-- Definir, por recursión, la función 
--    numeroBloquesR :: Integer -> Integer    
-- tal que (numeroBloquesR n) es el número de bloques necesarios para
-- construir una escalera con n escalones. Por ejemplo,
--    numeroBloquesR 1   == 2
--    numeroBloquesR 3   == 12
--    numeroBloquesR 10  == 110
-- ---------------------------------------------------------------------

--Sara Cerro, Ana Sosa Caballero
numeroBloquesR :: Integer -> Integer    
numeroBloquesR 1 = 2
numeroBloquesR n = 2*n + numeroBloquesR (n-1) 

-- ---------------------------------------------------------------------
-- Ejercicio 15.2. Definir, por comprensión, la función 
--    numeroBloquesC :: Integer -> Integer    
-- tal que (numeroBloquesC n) es el número de bloques necesarios para
-- construir una escalera con n escalones. Por ejemplo,
--    numeroBloquesC 1   == 2
--    numeroBloquesC 3   == 12
--    numeroBloquesC 10  == 110
-- ---------------------------------------------------------------------

--Sara Cerro, Ana Sosa Caballero
numeroBloquesC :: Integer -> Integer
numeroBloquesC n = sum [ 2*x | x <- xs]
          where xs = [1..n]
-- ---------------------------------------------------------------------
-- Ejercicio 15.3. Comprobar con QuickCheck que (numeroBloquesC n) es
-- igual a n+n^2.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_numeroBloquesR :: Integer -> Bool
prop_numeroBloquesR n =(abs n) + n^2 == numeroBloquesC (abs n)

prop_numeroBloquesR :: Integer -> Property
prop_numeroBloquesR n =
 n>=0 ==> n + n^2 == numeroBloquesC n

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 16. Definir la función 
--    esDigito :: Integer -> Integer -> Bool
-- tal que (esDigito x n) se verifica si x es un dígito de n. Por
-- ejemplo, 
--    esDigito 4 1041  ==  True
--    esDigito 3 1041  ==  False
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
digitos n | n<10 = [n]
          | otherwise = digitos (div n 10) ++ [rem n 10]

  
esDigito :: Integer -> Integer -> Bool
esDigito x n = elem x (digitos n)

-- Sara Cerro 
esDigito :: Integer -> Integer -> Bool
esDigito x n = elem x (convertirLista n)
convertirLista 0 = []
convertirLista n = [rem n 10] ++ convertirLista (div n 10) 

esDigito1 :: Integer -> Integer -> Bool
esDigito1 x n = elem  head(show x)  (show n)

-- ---------------------------------------------------------------------
-- Ejercicio 17. Definir la función
--    numeroDeDigitos :: Integer -> Integer
-- tal que (numeroDeDigitos x) es el número de dígitos de x. Por ejemplo,
--    numeroDeDigitos 34047  ==  5
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
numeroDeDigitos :: Integer -> Int
numeroDeDigitos x = length(digitos x)
-- NOTA: PRUEBA CON SHOW
-- Adolfo Sagrera Vivancos
numeroDeDigitos1 :: Integer -> Int
numeroDeDigitos1 x = sum [  1  | x <- cifras x]
cifras x = [read [c] :: Int | c <- show x]

-- ---------------------------------------------------------------------
-- Ejercicio 18.1 Definir, por recursión, la función 
--    listaNumeroR :: [Integer] -> Integer
-- tal que (listaNumeroR xs) es el número formado por los dígitos xs. Por
-- ejemplo, 
--    listaNumeroR [5]        == 5
--    listaNumeroR [1,3,4,7]  == 1347
--    listaNumeroR [0,0,1]    == 1
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero, Lucía González
listaNumeroR :: [Integer] -> Integer
listaNumeroR [x] = x
listaNumeroR (x:xs) = x*10^(length xs) + listaNumeroR xs

-- ---------------------------------------------------------------------
-- Ejercicio 18.2. Definir, por comprensión, la función 
--    listaNumeroC :: [Integer] -> Integer
-- tal que (listaNumeroC xs) es el número formado por los dígitos xs. Por
-- ejemplo, 
--    listaNumeroC [5]        == 5
--    listaNumeroC [1,3,4,7]  == 1347
--    listaNumeroC [0,0,1]    == 1
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero, Lucía González
listaNumeroC :: [Integer] -> Integer
listaNumeroC xs = sum [x*(10^s) | (x,s)<- zip xs ys]
                where ys = reverse [0..length xs-1]

-- ---------------------------------------------------------------------
-- Ejercicio 19.1. Definir, por recursión, la función 
--    pegaNumerosR :: Integer -> Integer -> Integer
-- tal que (pegaNumerosR x y) es el número resultante de "pegar" los
-- números x e y. Por ejemplo, 
--    pegaNumerosR 12 987   ==  12987
--    pegaNumerosR 1204 7   ==  12047
--    pegaNumerosR 100 100  ==  100100
-- ---------------------------------------------------------------------
-- AYUDA: HAZ RECURSIÓN EN EL SEGUNDO NÚMERO 
pegaNumerosR :: Integer -> Integer -> Integer
pegaNumerosR x y = undefined
-- T: DOS OPCIONES
pegaNumerosR1 :: Integer -> Integer -> Integer
pegaNumerosR1 x y = x * 10^length(digitosR y) + y
-- Sin usar dígitos recursiva, me da igual trabajar con caracteres ya que --- no voy a operar como números
pegaNumerosR2 :: Integer -> Integer -> Integer
pegaNumerosR2 x y = x * 10^(length (show y)) + y
-- Definición de pN recursiva:
pN x y | y<10 = x*10 + y
       | otherwise = (pN x (div y 10) ) * 10 + rem y 10
-- ---------------------------------------------------------------------
-- Ejercicio 19.2. Definir, sin usar recursión, la función 
--    pegaNumerosNR :: Integer -> Integer -> Integer
-- tal que (pegaNumerosNR x y) es el número resultante de "pegar" los
-- números x e y. Por ejemplo, 
--    pegaNumerosNR 12 987   ==  12987
--    pegaNumerosNR 1204 7   ==  12047
--    pegaNumerosNR 100 100  ==  100100
-- ---------------------------------------------------------------------
-- Lucía Hernández
pegaNumerosNR :: Integer -> Integer -> Integer
pegaNumerosNR x y = x*10^(length (digitos y)) + y
-- T:
-- ESA USA RECURSIÓN YA QUE DIGITOS ES RECURSIVA
-- PRUEBA A USAR SHOW READ o bien listanumeroR:
pegaNumerosNR1 :: Integer -> Integer -> Integer
pegaNumerosNR1 x y = read (show x ++ show y)

pegaNumerosNR :: Integer -> Integer -> Integer
pegaNumerosNR x y = listaNumeroR (digitosR x ++ digitosR y)
-- ---------------------------------------------------------------------
-- Ejercicio 19.3. Comprobar con QuickCheck que las funciones
-- pegaNumerosR y pegaNumerosNR son equivalentes.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_pegaNumeros x y = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 20.1. Definir, por recursión, la función 
--    primerDigitoR :: Integer -> Integer
-- tal que (primerDigitoR n) es el primer dígito de n. Por ejemplo, 
--    primerDigitoR 425  ==  4
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero, Lucía González
primerDigitoR :: Integer -> Integer
primerDigitoR n | n<10 = n
                | otherwise = primerDigitoR (div n 10)

-- ---------------------------------------------------------------------
-- Ejercicio 20.2. Definir, sin usar recursión, la función 
--    primerDigitoNR :: Integer -> Integer
-- tal que (primerDigitoNR n) es la primera digito de n. Por ejemplo, 
--    primerDigitoNR 425  ==  4
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero 
primerDigitoNR :: Integer -> Integer
primerDigitoNR n = head (digitos n) -- digitos era recursiva
pDNR n = read [(head (show n))] -- esta es sin recursión

--Lucía González 
primerDigitoNR :: Integer -> Integer
primerDigitoNR n = head [n]
-- ---------------------------------------------------------------------
-- Ejercicio 20.3. Comprobar con QuickCheck que las funciones
-- primerDigitoR y primerDigitoNR son equivalentes.
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero 
-- La propiedad es
prop_primerDigito x = primerDigitoR x == primerDigitoNR x

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 21.1. Definir la función 
--    inverso :: Integer -> Integer
-- tal que (inverso n) es el número obtenido escribiendo los dígitos de n
-- en orden inverso. Por ejemplo, 
--    inverso 42578  ==  87524
--    inverso 203    ==    302
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero 
inverso :: Integer -> Integer
inverso n = listaNumeroC (reverse (digitos n))

-- ---------------------------------------------------------------------
-- Ejercicio 22.2. Definir, usando show y read, la función 
--    inverso' :: Integer -> Integer
-- tal que (inverso' n) es el número obtenido escribiendo los dígitos de n
-- en orden inverso'. Por ejemplo, 
--    inverso' 42578  ==  87524
--    inverso' 203    ==    302
-- ---------------------------------------------------------------------

inverso' :: Integer -> Integer
inverso' n = read (reverse (show n))
-- Mejor:
inverso' = read.reverse.show

-- ---------------------------------------------------------------------
-- Ejercicio 22.3. Comprobar con QuickCheck que las funciones
-- inverso e inverso' son equivalentes.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_inverso n = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 23. Definir la función 
--    capicua :: Integer -> Bool
-- tal que (capicua n) se verifica si los dígitos de n son las mismas
-- de izquierda a derecha que de derecha a izquierda. Por ejemplo,
--    capicua 1234  =  False
--    capicua 1221  =  True
--    capicua 4     =  True
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero 
capicua :: Integer -> Bool
capicua n = reverse(digitos n) == digitos n
cap n = inverso' n == n
-- ---------------------------------------------------------------------
-- Ejercicio 24. (Problema 16 del proyecto Euler) El problema se
-- encuentra en http://goo.gl/4uWh y consiste en calcular la suma de los
-- dígitos de 2^1000. Lo resolveremos mediante los distintos apartados de
-- este ejercicio.  
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 24.1. Definir la función
--    euler16 :: Integer -> Integer
-- tal que (euler16 n) es la suma de los dígitos de 2^n. Por ejemplo,
--    euler16 4  ==  7
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
euler16 :: Integer -> Integer
euler16 n = sum(digitos (2^n))

-- ---------------------------------------------------------------------
-- Ejercicio 24.2. Calcular la suma de los dígitos de 2^1000.
-- ---------------------------------------------------------------------

-- El cálculo es
--    *Main> euler16 1000
--    1366

-- ---------------------------------------------------------------------
-- Ejercicio 25. En el enunciado de uno de los problemas de las
-- Olimpiadas matemáticas de Brasil se define el primitivo de un número
-- como sigue: 
--    Dado un número natural N, multiplicamos todos sus dígitos,
--    repetimos este procedimiento hasta que quede un solo dígito al
--    cual llamamos primitivo de N. Por ejemplo para 327: 3x2x7 = 42 y 
--    4x2 = 8. Por lo tanto, el primitivo de 327 es 8.
--
-- Definir la función 
--    primitivo :: Integer -> Integer
-- tal que (primitivo n) es el primitivo de n. Por ejemplo.
--    primitivo 327  ==  8
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sosa Caballero
primitivo :: Integer -> Integer
primitivo n | n<10 = n
            | otherwise = primitivo (product(digitos n))

-- ---------------------------------------------------------------------
-- Ejercicio 26. Dos números son equivalentes si la media de sus dígitos
-- son iguales. Por ejemplo, 3205 y 41 son equivalentes ya que 
-- (3+2+0+5)/4 = (4+1)/2. Definir la función 
--    equivalentes :: Integer -> Integer -> Bool
-- tal que (equivalentes x y) se verifica si los números x e y son
-- equivalentes. Por ejemplo,
--    equivalentes 3205 41  ==  True
--    equivalentes 3205 25  ==  False
-- ---------------------------------------------------------------------

equivalentes :: Integer -> Integer -> Bool
equivalentes x y = media1 x == media1 y
media1 x = sum(digitos x)  / fromIntegral( length (show x))
-- ---------------------------------------------------------------------
-- Ejercicio 27. Un número x es especial si el número de ocurrencias de
-- cada dígito d de x en x^2 es el doble del número de ocurrencias de d
-- en x. Por ejemplo, 72576 es especial porque tiene un 2, un 5, un 6 y
-- dos 7 y su cuadrado es 5267275776 que tiene exactamente dos 2, dos 5,
-- dos 6 y cuatro 7.
-- 
-- Definir la función
--    especial :: Integer -> Bool
-- tal que (especial x) se verifica si x es un número especial. Por
-- ejemplo,
--    especial 72576  ==  True
--    especial 12     ==  False
-- Calcular el menor número especial mayor que 72576.
-- ---------------------------------------------------------------------

especial :: Integer -> Bool
especial x = and [ocur d (x^2) == 2*(ocur d x)| d <-digitos x]
ocur x n = sum[1 | y <-digitos n, x==y]
-- El cálculo es