Acciones

Diferencia entre revisiones de «Relación 6 Sol»

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

(Página creada con «<source lang='haskell'> -- I1M 2021-22: -- Funciones de orden superior y definiciones por plegados (II) -- Departamento de Ciencias de la Computación e Inteligencia Artif…»)
 
 
Línea 1: Línea 1:
<source lang='haskell'>
<source lang='haskell'>
-- I1M 2021-22:  
-- I1M 2021-22:
-- Funciones de orden superior y definiciones por plegados (II)
-- Funciones de orden superior y definiciones por plegados (II)
-- Departamento de Ciencias de la Computación e Inteligencia Artificial
-- Departamento de Ciencias de la Computación e Inteligencia Artificial
Línea 29: Línea 29:
-- -----------------------------------------------------------------------------
-- -----------------------------------------------------------------------------


-- Álvaro Galisteo:
-- 1) por comprensión,
resultadoPosC :: (a -> Integer) -> [a] -> [a]
resultadoPosC :: (a -> Integer) -> [a] -> [a]
resultadoPosO :: (a -> Integer) -> [a] -> [a]
resultadoPosC f xs = [ ns | ns <- xs, f ns > 0]
resultadoPosR :: (a -> Integer) -> [a] -> [a]
resultadoPosF :: (a -> Integer) -> [a] -> [a]


resultadoPosC f xs = [x | x <- xs, f x > 0]
-- 2) por orden superior,
resultadoPosOS :: (a -> Integer) -> [a] -> [a]
resultadoPosOS f xs = filter (\ x -> f x > 0) xs


resultadoPosO f xs = filter (\ x -> f x > 0) xs
-- 3) por recursión,
resultadoPosR :: (a -> Integer) -> [a] -> [a]
resultadoPosR _ [] = []
resultadoPosR f (x:xs) = if f x > 0 then x:resultadoPosR f xs
                            else resultadoPosR f xs  


resultadoPosR f [] = []
-- 4) por plegado.
resultadoPosR f (x:xs) | f x > 0 = x:resultadoPosR f xs
resultadoPosP :: (a -> Integer) -> [a] -> [a]
                      | otherwise = resultadoPosR f xs
resultadoPosP f xs = foldr (\ x y -> if f x > 0 then (x:y) else y ) [] xs
                     
resultadoPosF f xs = foldr (\ x y -> if f x > 0 then (x:y) else y) [] xs
 
prop_resultadoPos :: Eq a => (a -> Integer) -> [a] -> Bool
prop_resultadoPos f xs = resultadoPosC f xs == resultadoPosO f xs &&
                        resultadoPosC f xs == resultadoPosR f xs &&
                        resultadoPosC f xs == resultadoPosF f xs
 
-- Se probaría con
-- λ> quickCheck (prop_resultadoPos sum)
-- +++ OK, passed 100 tests.


-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
Línea 69: Línea 65:
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------


-- Álvaro Galisteo:
-- 1) por comprensión,
intercalaC :: Int -> [Int] -> [Int]
intercalaC :: Int -> [Int] -> [Int]
intercalaO :: Int -> [Int] -> [Int]
intercalaC n xs = concat [if x < n then [n,x] else [x] | x <- xs]
intercalaR :: Int -> [Int] -> [Int]
intercalaF :: Int -> [Int] -> [Int]


intercalaC y xs = concat [if x < y then [y,x] else [x] | x <- xs]
-- 2) por orden superior,
 
intercalaOS :: Int -> [Int] -> [Int]
intercalaO y xs = concat (map (\ x -> if x < y then [y,x] else [x]) xs)
intercalaOS n xs = concat (map (\ x -> if x<n then [n,x] else [x]) xs)


intercalaR y [] = []
-- 3) por recursión,
intercalaR y (x:xs) | x < y = y:x:intercalaR y xs
intercalaR :: Int -> [Int] -> [Int]
                    | otherwise = x:intercalaR y xs
intercalaR _ [] = []
intercalaR n (x:xs) = if x<n then [n,x]++intercalaR n xs
                            else [x]++intercalaR n xs  


intercalaF y xs = foldr (\ x l -> if x < y then y:x:l else x:l ) [] xs


prop_intercala :: Int -> [Int] -> Bool
-- 4) por plegado.
prop_intercala y xs = intercalaC y xs == intercalaO y xs &&
intercalaP :: Int -> [Int] -> [Int]
                      intercalaC y xs == intercalaR y xs &&
intercalaP n xs = foldl (\ x y -> if y < n then x++[n,y] else x++[y]) [] xs
                      intercalaC y xs == intercalaF y xs  


-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
Línea 104: Línea 101:
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------


-- Álvaro Galisteo:
-- 1) por comprensión,
dec2entC :: [Integer] -> Integer
dec2entC :: [Integer] -> Integer
dec2entO :: [Integer] -> Integer
dec2entC xs = sum [x*10^y | (x,y) <- zip xs (reverse [0..(length xs - 1)])]
dec2entR :: [Integer] -> Integer
dec2entF :: [Integer] -> Integer


dec2entC xs = read [head (show x) | x <- xs]
-- 2) por orden superior,
dec2entOS :: [Integer] -> Integer
dec2entOS xs = read (concat (map show xs)) :: Integer


dec2entO xs = read (map (head.show) xs)
-- 3) por recursión,
dec2entR :: [Integer] -> Integer
dec2entR xs = dec2entR' xs (length xs - 1)


dec2entR [] = 0
dec2entR' :: [Integer] -> Int -> Integer
dec2entR (x:xs) = x*10^(length xs) + dec2entR xs  
dec2entR' [] _ = 0  
dec2entR' (x:xs) n = x*10^n + dec2entR' xs (n-1)


dec2entF xs = foldl (\ x y -> 10*x + y) 0 xs
-- 4) por plegado.
dec2entP :: [Integer] -> Integer
dec2entP xs = foldl (\ x y -> x*10 + y) 0 xs  


prop_dec2ent :: [Integer] -> Property
prop_dec2ent xs = (all (\ x -> (x>0) && (x<10)) xs) && length xs > 0 ==>
                  dec2entC xs == dec2entO xs &&
                  dec2entC xs == dec2entR xs &&
                  dec2entC xs == dec2entF xs
                                   
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
-- Ejercicio 4. Se considera la función
-- Ejercicio 4. Se considera la función
Línea 141: Línea 140:
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------


-- Álvaro Galisteo:
-- 1) por comprensión,
diferenciaC :: Eq a => [a] -> [a] -> [a]
diferenciaC :: Eq a => [a] -> [a] -> [a]
diferenciaO :: Eq a => [a] -> [a] -> [a]
diferenciaC xs ys = [x | x <- xs, notElem x ys]
diferenciaR :: Eq a => [a] -> [a] -> [a]
diferenciaF :: Eq a => [a] -> [a] -> [a]


diferenciaC xs ys = [x | x <- xs, not (elem x ys) ]
-- 2) por orden superior,
 
diferenciaOS :: Eq a => [a] -> [a] -> [a]
diferenciaO xs ys = filter (\ x -> not (elem x ys)) xs
diferenciaOS xs ys = filter (\ x -> notElem x ys) xs


-- 3) por recursión,
diferenciaR :: Eq a => [a] -> [a] -> [a]
diferenciaR [] ys = []
diferenciaR [] ys = []
diferenciaR (x:xs) ys | elem x ys = diferenciaR xs ys
diferenciaR (x:xs) ys = if notElem x ys then x:diferenciaR xs ys
                      | otherwise = x:diferenciaR xs ys
                            else diferenciaR xs ys  
                       
diferenciaF xs ys = foldr (\ x l -> if elem x ys then l else x:l) [] xs


prop_diferencia :: Eq a => [a] -> [a] -> Bool
-- 4) por plegado.
prop_diferencia xs ys = diferenciaC xs ys == diferenciaO xs ys &&
diferenciaP :: Eq a => [a] -> [a] -> [a]
                        diferenciaC xs ys == diferenciaR xs ys &&
diferenciaP xs ys = foldr (\ x y -> if notElem x ys then x:y else y) [] xs
                        diferenciaC xs ys == diferenciaF xs ys


-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
Línea 178: Línea 177:
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------


-- Álvaro Galisteo:
-- 1) por comprensión,
primerosYultimosC :: [[a]] -> ([a],[a])
primerosYultimosC :: [[a]] -> ([a],[a])
primerosYultimosO :: [[a]] -> ([a],[a])
primerosYultimosC xss = ([head xs | xs <- xss, not (null xs)], [last xs | xs <- xss, not (null xs)])
primerosYultimosR :: [[a]] -> ([a],[a])
primerosYultimosF :: [[a]] -> ([a],[a])


primerosYultimosC xss = ([head xs | xs <- xss, length xs > 0],[last xs | xs <- xss, length xs > 0])
-- 2) por orden superior,
primerosYultimosOS :: [[a]] -> ([a],[a])
primerosYultimosOS xss = (map head (filter (not . null) xss), map last (filter (not . null) xss))


primerosYultimosO xss = (map head (filter (not.null) xss),map last (filter (not.null) xss))
-- 3) por recursión,
primerosYultimosR :: [[a]] -> ([a],[a])
primerosYultimosR xss = (primeros xss, ultimos xss)


primerosYultimosR xss = (primerosR xss, ultimosR xss)
primeros, ultimos :: [[a]] -> [a]


primerosR :: [[a]] -> [a]
primeros [] = []
primerosR [] = []
primeros (xs:xss) = if null xs then primeros xss else [head xs] ++ primeros xss
primerosR ([]:xss) = primerosR xss
primerosR (xs:xss) = head xs:primerosR xss


ultimosR :: [[a]] -> [a]
ultimos [] = []
ultimosR [] = []
ultimos (xs:xss) = if null xs then ultimos xss else [last xs] ++ ultimos xss
ultimosR ([]:xss) = primerosR xss
ultimosR (xs:xss) = last xs:primerosR xss


primerosYultimosF xss = (foldr (\ xs l -> if not (null xs) then (head xs):l else l) [] xss,
-- 4) por plegado.
                         foldr (\ xs l -> if not (null xs) then (last xs):l else l) [] xss)
primerosYultimosP :: [[a]] -> ([a],[a])
primerosYultimosP xss = (foldl (\ xs ys -> if not (null ys) then xs ++ [head ys] else xs) [] xss,
                         foldl (\ xs ys -> if not (null ys) then xs ++ [last ys] else xs) [] xss)


prop_primerosYultimos :: Eq a => [[a]] -> Bool
prop_primerosYultimos xss = primerosYultimosC xss == primerosYultimosO xss &&
                            primerosYultimosC xss == primerosYultimosR xss &&
                            primerosYultimosC xss == primerosYultimosF xss
                           
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
-- Ejercicio 6. Una lista hermanada es una lista de números estrictamente
-- Ejercicio 6. Una lista hermanada es una lista de números estrictamente
Línea 229: Línea 226:
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------


-- Álvaro Galisteo:
-- 1) por comprensión,
hermanadaC :: [Int] -> Bool
hermanadaC :: [Int] -> Bool
hermanadaO :: [Int] -> Bool
hermanadaC xs = and [gcd x y > 1 | (x,y) <- zip xs (tail xs), x /= 1, y /= 1]  
hermanadaR :: [Int] -> Bool
hermanadaF :: [Int] -> Bool


hermanadaC xs = and [x == 1 || y == 1 || gcd x y > 1 | (x,y) <- zip xs (tail xs)]
-- 2) por orden superior,
hermanadaOS :: [Int] -> Bool
hermanadaOS xs = and (map (\ (x,y) -> if x == 1 || y == 1 then True else gcd x y > 1) (zip xs (tail xs)))


hermanadaO xs = all (\ (x,y) -> x == 1 || y == 1 || gcd x y > 1) (zip xs (tail xs))
-- 3) por recursión,
               
hermanadaR :: [Int] -> Bool
hermanadaR [] = True
hermanadaR [_] = True
hermanadaR (x:[]) = True
hermanadaR (x:y:xs) = if x == 1 || y == 1 then True  && hermanadaR (y:xs) else gcd x y > 1 && hermanadaR (y:xs)  
hermanadaR (x:y:xs) = (x == 1 || y == 1 || gcd x y > 1) && hermanadaR (y:xs)


hermanadaF xs = foldr (\ (x,y) l -> (x == 1 || y == 1 || gcd x y > 1) && l) True (zip xs (tail xs))
-- 4) por plegado.
hermanadaP :: [Int] -> Bool
hermanadaP xs = foldr (\ (x,y) l -> (x == 1 || y == 1 || gcd x y > 1) && l) True (zip xs (tail xs))


prop_hermanadas :: [Int] -> Property
prop_hermanadas xs = all (>0) xs ==> hermanadaC xs == hermanadaO xs &&
                                    hermanadaC xs == hermanadaR xs &&
                                    hermanadaC xs == hermanadaF xs


-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
Línea 266: Línea 263:
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------


permanenteC :: [Int] -> [Int]
-- Álvaro Galisteo:  
permanenteO :: [Int] -> [Int]
permanenteR :: [Int] -> [Int]
permanenteF :: [Int] -> [Int]


permanenteC xs = [x | (x,y) <- zip xs (tail (tails xs)), all (x>) y]
-- 1) por comprensión,
permanentesC :: [Int] -> [Int]
permanentesC xs = [x | (x,y) <- zip xs (tails xs), x == maximum y]


permanenteO xs = map fst (filter (\ (x,y) -> all (x>) y) (zip xs (tail (tails xs))))
-- 2) por orden superior,
permanentesOS :: [Int] -> [Int]
permanentesOS xs = concat (map (\ (x,y) -> if x == maximum y then [x] else []) (zip xs (tails xs)))  


permanenteR [] = []
-- 3) por recursión,
permanenteR (x:xs) | all (x>) xs = x:permanenteR xs
permanentesR :: [Int] -> [Int]
                  | otherwise = permanenteR xs
permanentesR [x] = [x]
permanentesR (x:xs) = if all (<x) xs then x:permanentesR xs else permanentesR xs


permanenteF xs = foldr (\ (x,y) l -> if all (x>) y then x:l else l) [] (zip xs (tail (tails xs)))
-- 4) por plegado.
permanentesP :: [Int] -> [Int]
permanentesP xs = foldr (\ x y -> if all (<x) y then x:y else y) [] xs


prop_permanente :: [Int] -> Bool
             
prop_permanente xs = permanenteC xs == permanenteO xs &&
                    permanenteC xs == permanenteR xs &&
                    permanenteC xs == permanenteF xs
 
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
-- Ejercicio 8. Un número entero positivo n es muy primo si es n primo
-- Ejercicio 8. Un número entero positivo n es muy primo si es n primo
Línea 299: Línea 296:
-- --------------------------------------------------------------------
-- --------------------------------------------------------------------


factores :: Int -> [Int]
-- Álvaro Galisteo:
factores n = [x | x <- [1..n], n `mod` x == 0]


primo :: Int -> Bool
primo :: Int -> Bool
primo n = factores n == [1,n]
primo 1 = False
primo x = and [gcd n x == 1| n <- [2..(x-1)]]


muyPrimo :: Int -> Bool
muyPrimo :: Int -> Bool
muyPrimo n | n < 10 = primo n
muyPrimo x = and [primo n | n <- listaNumero x]
          | otherwise = primo n && muyPrimo (n `div` 10)
 
listaNumero :: Int -> [Int]
listaNumero x | x < 10 = [x]
              | otherwise = x:listaNumero (div x 10)  


-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------
Línea 313: Línea 313:
-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------


-- El cálculo es:
-- Álvaro Galisteo:
-- λ> sum [1 | x <- [10000..99999], muyPrimo x]
 
-- El cálculo es
 
muyPrimosDeCincoCifras :: Int
muyPrimosDeCincoCifras = sum [1 | x <- [10000..99999], primo (div x 10000) && primo (div x 1000) && primo (div x 100)&& primo (div x 10) && primo x]
 
-- *Main> muyPrimosDeCincoCifras
-- 15
-- 15
-- (232.02 secs, 94,736,606,016 bytes)
 


-- ---------------------------------------------------------------------
-- ---------------------------------------------------------------------


</source>
</source>

Revisión actual del 19:44 16 ene 2022

-- I1M 2021-22:
-- Funciones de orden superior y definiciones por plegados (II)
-- Departamento de Ciencias de la Computación e Inteligencia Artificial
-- Universidad de Sevilla
-- ============================================================================

-- ============================================================================
-- Librerías auxiliares
-- ============================================================================

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

-- ----------------------------------------------------------------------------
-- Ejercicio 1. Se considera la función
--      resultadoPos :: (a -> Integer) -> [a] -> [a]
-- tal que (resultadoPos f xs) es la lista de los elementos de la lista
-- xs tales que el valor de la función f sobre ellos es positivo. Por ejemplo,
--   resultadoPos head [[-1,2],[-9,4],[2,3]]       ==  [[2,3]]
--   resultadoPos sum [[1,2],[9],[-8,3],[],[3,5]]  ==  [[1,2],[9],[3,5]]
--
-- Define esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- -----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
resultadoPosC :: (a -> Integer) -> [a] -> [a]
resultadoPosC f xs = [ ns | ns <- xs, f ns > 0]

-- 2) por orden superior,
resultadoPosOS :: (a -> Integer) -> [a] -> [a]
resultadoPosOS f xs = filter (\ x -> f x > 0) xs

-- 3) por recursión,
resultadoPosR :: (a -> Integer) -> [a] -> [a]
resultadoPosR _ [] = []
resultadoPosR f (x:xs) = if f x > 0 then x:resultadoPosR f xs
                            else resultadoPosR f xs 

-- 4) por plegado.
resultadoPosP :: (a -> Integer) -> [a] -> [a]
resultadoPosP f xs = foldr (\ x y -> if f x > 0 then (x:y) else y ) [] xs

-- ----------------------------------------------------------------------------
-- Ejercicio 2. Se considera la función
--     intercala :: Int -> [Int] -> [Int]
-- tal que (intercala y xs) es la lista que resulta de intercalar el elemento
-- y delante de todos los elementos de la lista xs que sean menores que y.
-- Por ejemplo,
--   intercala 5 [1,2,6,3,7,9]  ==  [5,1,5,2,6,5,3,7,9]
--   intercala 5 [6,7,9,8]      ==  [6,7,9,8]
--
-- Define esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
intercalaC :: Int -> [Int] -> [Int]
intercalaC n xs = concat [if x < n then [n,x] else [x] | x <- xs]

-- 2) por orden superior,
intercalaOS :: Int -> [Int] -> [Int]
intercalaOS n xs = concat (map (\ x -> if x<n then [n,x] else [x]) xs)

-- 3) por recursión,
intercalaR :: Int -> [Int] -> [Int]
intercalaR _ [] = []
intercalaR n (x:xs) = if x<n then [n,x]++intercalaR n xs
                             else [x]++intercalaR n xs 


-- 4) por plegado.
intercalaP :: Int -> [Int] -> [Int]
intercalaP n xs = foldl (\ x y -> if y < n then x++[n,y] else x++[y]) [] xs

-- ----------------------------------------------------------------------------
-- Ejercicio 3. Se considera la función
--    dec2ent :: [Integer] -> Integer
-- tal que (dec2ent xs) es el número entero cuyas cifras ordenadas son los
-- elementos de la lista xs. Por ejemplo,
--   dec2ent [2,3,4,5]  ==  2345
--   dec2ent [1..9]     ==  123456789
--
-- Defie esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
dec2entC :: [Integer] -> Integer
dec2entC xs = sum [x*10^y | (x,y) <- zip xs (reverse [0..(length xs - 1)])]

-- 2) por orden superior,
dec2entOS :: [Integer] -> Integer
dec2entOS xs = read (concat (map show xs)) :: Integer

-- 3) por recursión,
dec2entR :: [Integer] -> Integer
dec2entR xs = dec2entR' xs (length xs - 1)

dec2entR' :: [Integer] -> Int -> Integer
dec2entR' [] _ = 0 
dec2entR' (x:xs) n = x*10^n + dec2entR' xs (n-1)

-- 4) por plegado.
dec2entP :: [Integer] -> Integer
dec2entP xs = foldl (\ x y -> x*10 + y) 0 xs 

-- ----------------------------------------------------------------------------
-- Ejercicio 4. Se considera 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, el conjunto de los elementos de la lista xs que no se
-- encuentran en la lista ys. Por ejemplo,
--   diferencia [2,3,5,6] [5,2,7]  ==  [3,6]
--   diferencia [1,3,5,7] [2,4,6]  ==  [1,3,5,7]
--   diferencia [1,3] [1..9]       ==  []
--
-- Define esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
diferenciaC :: Eq a => [a] -> [a] -> [a]
diferenciaC xs ys = [x | x <- xs, notElem x ys]

-- 2) por orden superior,
diferenciaOS :: Eq a => [a] -> [a] -> [a]
diferenciaOS xs ys = filter (\ x -> notElem x ys) xs

-- 3) por recursión,
diferenciaR :: Eq a => [a] -> [a] -> [a]
diferenciaR [] ys = []
diferenciaR (x:xs) ys = if notElem x ys then x:diferenciaR xs ys
                             else diferenciaR xs ys 

-- 4) por plegado.
diferenciaP :: Eq a => [a] -> [a] -> [a]
diferenciaP xs ys = foldr (\ x y -> if notElem x ys then x:y else y) [] xs

-- ----------------------------------------------------------------------------
-- Ejercicio 5. Se considera la función
--   primerosYultimos :: [[a]] -> ([a],[a])
-- tal que (primerosYultimos xss) es el par formado por la lista de los
-- primeros elementos de las listas no vacías de xss y la lista de los
-- últimos elementos de las listas no vacías de xss. Por ejemplo,
--   primerosYultimos [[1,2],[5,3,4],[],[9]]  ==  ([1,5,9],[2,4,9])
--   primerosYultimos [[1,2],[1,2,3],[1..4]]  ==  ([1,1,1],[2,3,4])

--
-- Define esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
primerosYultimosC :: [[a]] -> ([a],[a])
primerosYultimosC xss = ([head xs | xs <- xss, not (null xs)], [last xs | xs <- xss, not (null xs)])

-- 2) por orden superior,
primerosYultimosOS :: [[a]] -> ([a],[a])
primerosYultimosOS xss = (map head (filter (not . null) xss), map last (filter (not . null) xss))

-- 3) por recursión,
primerosYultimosR :: [[a]] -> ([a],[a])
primerosYultimosR xss = (primeros xss, ultimos xss)

primeros, ultimos :: [[a]] -> [a]

primeros [] = []
primeros (xs:xss) = if null xs then primeros xss else [head xs] ++ primeros xss

ultimos [] = []
ultimos (xs:xss) = if null xs then ultimos xss else [last xs] ++ ultimos xss

-- 4) por plegado.
primerosYultimosP :: [[a]] -> ([a],[a])
primerosYultimosP xss = (foldl (\ xs ys -> if not (null ys)  then xs ++ [head ys] else xs) [] xss,
                         foldl (\ xs ys -> if not (null ys) then xs ++ [last ys] else xs) [] xss)

-- ----------------------------------------------------------------------------
-- Ejercicio 6. Una lista hermanada es una lista de números estrictamente
-- positivos en la que cada elemento tiene algún factor primo en común con el
-- siguiente, en caso de que exista, o alguno de los dos es un 1. Por ejemplo,
-- [2,6,3,9,1,5] es una lista hermanada.

-- Se considera la función
--    hermanada :: [Int] -> Bool
-- tal que (hermanada xs) comprueba que la lista xs es hermanada según la
-- definición anterior. Por ejemplo,
--    hermanada [2,6,3,9,1,5]  ==  True
--    hermanada [2,3,5]        ==  False
--
-- Se pide definir esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- ----------------------------------------------------------------------------
-- Nota: Usa la función 'gcd'
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
hermanadaC :: [Int] -> Bool
hermanadaC xs = and [gcd x y > 1 | (x,y) <- zip xs (tail xs), x /= 1, y /= 1] 

-- 2) por orden superior,
hermanadaOS :: [Int] -> Bool
hermanadaOS xs = and (map (\ (x,y) -> if x == 1 || y == 1 then True else gcd x y > 1) (zip xs (tail xs)))

-- 3) por recursión,
hermanadaR :: [Int] -> Bool
hermanadaR [_] = True
hermanadaR (x:y:xs) =  if x == 1 || y == 1 then True  && hermanadaR (y:xs) else gcd x y > 1 && hermanadaR (y:xs) 

-- 4) por plegado.
hermanadaP :: [Int] -> Bool
hermanadaP xs = foldr (\ (x,y) l -> (x == 1 || y == 1 || gcd x y > 1) && l) True (zip xs (tail xs))


-- ----------------------------------------------------------------------------
-- Ejercicio 7. Un elemento de una lista es permanente si ninguno de los que
-- vienen a continuación en la lista es mayor que él. Consideramos la función
--   permanentes :: [Int] -> [Int]
-- tal que (permanentes xs) es la lista de los elementos permanentes de la
-- lista xs. Por ejemplo,
--   permanentes [80,1,7,8,4]  ==  [80,8,4]

-- Se pide definir esta función
-- 1) por comprensión,
-- 2) por orden superior,
-- 3) por recursión,
-- 4) por plegado.
-- ---------------------------------------------------------------------------
-- Nota: Usa la función 'tails' de Data.List.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 1) por comprensión,
permanentesC :: [Int] -> [Int]
permanentesC xs = [x | (x,y) <- zip xs (tails xs), x == maximum y]

-- 2) por orden superior,
permanentesOS :: [Int] -> [Int]
permanentesOS xs = concat (map (\ (x,y) -> if x == maximum y then [x] else []) (zip xs (tails xs))) 

-- 3) por recursión,
permanentesR :: [Int] -> [Int]
permanentesR [x] = [x]
permanentesR (x:xs) = if all (<x) xs then x:permanentesR xs else permanentesR xs

-- 4) por plegado.
permanentesP :: [Int] -> [Int]
permanentesP xs = foldr (\ x y -> if all (<x) y then x:y else y) [] xs

               
-- ---------------------------------------------------------------------
-- Ejercicio 8. Un número entero positivo n es muy primo si es n primo
-- y todos los números que resultan de ir suprimimiendo la última cifra
-- también son primos. Por ejemplo, 7193 es muy primo pues los números
-- 7193, 719, 71 y 7 son todos primos. 
-- 
-- Define la función 
--    muyPrimo :: Integer -> Bool
-- que (muyPrimo n) se verifica si n es muy primo. Por ejemplo,
--    muyPrimo 7193  == True
--    muyPrimo 71932 == False
-- --------------------------------------------------------------------

-- Álvaro Galisteo: 

primo :: Int -> Bool
primo 1 = False 
primo x = and [gcd n x == 1| n <- [2..(x-1)]]

muyPrimo :: Int -> Bool
muyPrimo x = and [primo n | n <- listaNumero x]

listaNumero :: Int -> [Int]
listaNumero x | x < 10 = [x]
              | otherwise = x:listaNumero (div x 10) 

-- ---------------------------------------------------------------------
-- ¿Cuántos números de cinco cifras son muy primos?
-- ---------------------------------------------------------------------

-- Álvaro Galisteo: 

-- El cálculo es

muyPrimosDeCincoCifras :: Int
muyPrimosDeCincoCifras = sum [1 | x <- [10000..99999], primo (div x 10000) && primo (div x 1000) && primo (div x 100)&& primo (div x 10) && primo x]

-- *Main> muyPrimosDeCincoCifras
-- 15


-- ---------------------------------------------------------------------