-- 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