# Etiqueta: Data.List

## Clausura de un conjunto respecto de una función

Un conjunto A está cerrado respecto de una función f si para elemento x de A se tiene que f(x) pertenece a A. La clausura de un conjunto B respecto de una función f es el menor conjunto A que contiene a B y es cerrado respecto de f. Por ejemplo, la clausura de {0,1,2] respecto del opuesto es {-2,-1,0,1,2}.

Definir la función

` clausura :: Ord a => (a -> a) -> [a] -> [a]`

tal que `(clausura f xs)` es la clausura de `xs` respecto de f. Por ejemplo,

``` clausura (\x -> -x) [0,1,2] == [-2,-1,0,1,2] clausura (\x -> (x+1) `mod` 5) [0] == [0,1,2,3,4] length (clausura (\x -> (x+1) `mod` (10^6)) [0]) == 1000000```

#### Soluciones

```module Clausura where   import Data.List ((\\), nub, sort, union) import Test.QuickCheck.HigherOrder (quickCheck') import qualified Data.Set as S (Set, difference, fromList, map, null, toList, union)   -- 1ª solución -- ===========   clausura1 :: Ord a => (a -> a) -> [a] -> [a] clausura1 f xs | esCerrado f xs = sort xs | otherwise = clausura1 f (expansion f xs)   -- (esCerrado f xs) se verifica si al aplicar f a cualquier elemento de -- xs se obtiene un elemento de xs. Por ejemplo, -- λ> esCerrado (\x -> -x) [0,1,2] -- False -- λ> esCerrado (\x -> -x) [0,1,2,-2,-1] -- True esCerrado :: Ord a => (a -> a) -> [a] -> Bool esCerrado f xs = all (`elem` xs) (map f xs)   -- (expansion f xs) es la lista (sin repeticiones) obtenidas añadiéndole -- a xs el resulta de aplicar f a sus elementos. Por ejemplo, -- expansion (\x -> -x) [0,1,2] == [0,1,2,-1,-2] expansion :: Ord a => (a -> a) -> [a] -> [a] expansion f xs = xs `union` map f xs   -- 2ª solución -- ===========   clausura2 :: Ord a => (a -> a) -> [a] -> [a] clausura2 f xs = sort (until (esCerrado f) (expansion f) xs)   -- 3ª solución -- ===========   clausura3 :: Ord a => (a -> a) -> [a] -> [a] clausura3 f xs = aux xs xs where aux ys vs | null ns = sort vs | otherwise = aux ns (vs ++ ns) where ns = nub (map f ys) \\ vs   -- 4ª solución -- ===========   clausura4 :: Ord a => (a -> a) -> [a] -> [a] clausura4 f xs = S.toList (clausura4' f (S.fromList xs))   clausura4' :: Ord a => (a -> a) -> S.Set a -> S.Set a clausura4' f xs = aux xs xs where aux ys vs | S.null ns = vs | otherwise = aux ns (vs `S.union` ns) where ns = S.map f ys `S.difference` vs   -- Comprobación de equivalencia -- ============================   -- La propiedad es prop_clausura :: (Int -> Int) -> [Int] -> Bool prop_clausura f xs = all (== clausura1 f xs') [ clausura2 f xs' , clausura3 f xs' , clausura4 f xs' ] where xs' = sort (nub xs)   -- La comprobación es -- λ> quickCheck' prop_clausura -- +++ OK, passed 100 tests.   -- Comparación de eficiencia -- =========================   -- La comparación es -- λ> length (clausura1 (\x -> (x+1) `mod` 800) [0]) -- 800 -- (1.95 secs, 213,481,560 bytes) -- λ> length (clausura2 (\x -> (x+1) `mod` 800) [0]) -- 800 -- (1.96 secs, 213,372,824 bytes) -- λ> length (clausura3 (\x -> (x+1) `mod` 800) [0]) -- 800 -- (0.03 secs, 42,055,128 bytes) -- λ> length (clausura4 (\x -> (x+1) `mod` 800) [0]) -- 800 -- (0.01 secs, 1,779,768 bytes) -- -- λ> length (clausura3 (\x -> (x+1) `mod` (10^4)) [0]) -- 10000 -- (2.50 secs, 8,080,105,816 bytes) -- λ> length (clausura4 (\x -> (x+1) `mod` (10^4)) [0]) -- 10000 -- (0.05 secs, 27,186,920 bytes)```

El código se encuentra en GitHub.

La elaboración de las soluciones se describe en el siguiente vídeo

## Representación de Zeckendorf

Los primeros números de Fibonacci son

` 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, ...`

tales que los dos primeros son iguales a 1 y los siguientes se obtienen sumando los dos anteriores.

El teorema de Zeckendorf establece que todo entero positivo n se puede representar, de manera única, como la suma de números de Fibonacci no consecutivos decrecientes. Dicha suma se llama la representación de Zeckendorf de n. Por ejemplo, la representación de Zeckendorf de 100 es

` 100 = 89 + 8 + 3`

Hay otras formas de representar 100 como sumas de números de Fibonacci; por ejemplo,

``` 100 = 89 + 8 + 2 + 1 100 = 55 + 34 + 8 + 3```

pero no son representaciones de Zeckendorf porque 1 y 2 son números de Fibonacci consecutivos, al igual que 34 y 55.

Definir la función

` zeckendorf :: Integer -> [Integer]`

tal que `(zeckendorf n)` es la representación de Zeckendorf de `n`. Por ejemplo,

``` zeckendorf 100 == [89,8,3] zeckendorf 200 == [144,55,1] zeckendorf 300 == [233,55,8,3,1] length (zeckendorf (10^50000)) == 66097```

#### Soluciones

```module Representacion_de_Zeckendorf where   import Data.List (subsequences) import Test.QuickCheck   -- 1ª solución -- ===========   zeckendorf1 :: Integer -> [Integer] zeckendorf1 = head . zeckendorf1Aux   zeckendorf1Aux :: Integer -> [[Integer]] zeckendorf1Aux n = [xs | xs <- subsequences (reverse (takeWhile (<= n) (tail fibs))), sum xs == n, sinFibonacciConsecutivos xs]   -- fibs es la la sucesión de los números de Fibonacci. Por ejemplo, -- take 14 fibs == [1,1,2,3,5,8,13,21,34,55,89,144,233,377] fibs :: [Integer] fibs = 1 : scanl (+) 1 fibs -- (sinFibonacciConsecutivos xs) se verifica si en la sucesión -- decreciente de número de Fibonacci xs no hay dos consecutivos. Por -- ejemplo,   -- (sinFibonacciConsecutivos xs) se verifica si en la sucesión -- decreciente de número de Fibonacci xs no hay dos consecutivos. Por -- ejemplo, -- sinFibonacciConsecutivos [89, 8, 3] == True -- sinFibonacciConsecutivos [55, 34, 8, 3] == False sinFibonacciConsecutivos :: [Integer] -> Bool sinFibonacciConsecutivos xs = and [x /= siguienteFibonacci y | (x,y) <- zip xs (tail xs)]   -- (siguienteFibonacci n) es el menor número de Fibonacci mayor que -- n. Por ejemplo, -- siguienteFibonacci 34 == 55 siguienteFibonacci :: Integer -> Integer siguienteFibonacci n = head (dropWhile (<= n) fibs)   -- 2ª solución -- ===========   zeckendorf2 :: Integer -> [Integer] zeckendorf2 = head . zeckendorf2Aux   zeckendorf2Aux :: Integer -> [[Integer]] zeckendorf2Aux n = map reverse (aux n (tail fibs)) where aux 0 _ = [[]] aux m (x:y:zs) | x <= m = [x:xs | xs <- aux (m-x) zs] ++ aux m (y:zs) | otherwise = []   -- 3ª solución -- ===========   zeckendorf3 :: Integer -> [Integer] zeckendorf3 0 = [] zeckendorf3 n = x : zeckendorf3 (n - x) where x = last (takeWhile (<= n) fibs)   -- 4ª solución -- ===========   zeckendorf4 :: Integer -> [Integer] zeckendorf4 n = aux n (reverse (takeWhile (<= n) fibs)) where aux 0 _ = [] aux m (x:xs) = x : aux (m-x) (dropWhile (>m-x) xs)   -- Comprobación de equivalencia -- ============================   -- La propiedad es prop_zeckendorf :: Positive Integer -> Bool prop_zeckendorf (Positive n) = all (== zeckendorf1 n) [zeckendorf2 n, zeckendorf3 n, zeckendorf4 n]   -- La comprobación es -- λ> quickCheck prop_zeckendorf -- +++ OK, passed 100 tests.   -- Comparación de eficiencia -- =========================   -- La comparación es -- λ> zeckendorf1 (7*10^4) -- [46368,17711,4181,1597,89,34,13,5,2] -- (1.49 secs, 2,380,707,744 bytes) -- λ> zeckendorf2 (7*10^4) -- [46368,17711,4181,1597,89,34,13,5,2] -- (0.07 secs, 21,532,008 bytes) -- -- λ> zeckendorf2 (10^6) -- [832040,121393,46368,144,55] -- (1.40 secs, 762,413,432 bytes) -- λ> zeckendorf3 (10^6) -- [832040,121393,46368,144,55] -- (0.01 secs, 542,488 bytes) -- λ> zeckendorf4 (10^6) -- [832040,121393,46368,144,55] -- (0.01 secs, 536,424 bytes) -- -- λ> length (zeckendorf3 (10^3000)) -- 3947 -- (3.02 secs, 1,611,966,408 bytes) -- λ> length (zeckendorf4 (10^2000)) -- 2611 -- (0.02 secs, 10,434,336 bytes) -- -- λ> length (zeckendorf4 (10^50000)) -- 66097 -- (2.84 secs, 3,976,483,760 bytes)```

El código se encuentra en GitHub.

La elaboración de las soluciones se describe en el siguiente vídeo

Se dice que una sucesión x(1), …, x(n) está ordenada cíclicamente si existe un índice i tal que la sucesión

` x(i), x(i+1), ..., x(n), x(1), ..., x(i-1)`

está ordenada crecientemente de forma estricta.

Definir la función

` ordenadaCiclicamente :: Ord a => [a] -> Maybe Int`

tal que `(ordenadaCiclicamente xs)` es el índice a partir del cual está ordenada, si la lista está ordenado cíclicamente y `Nothing` en caso contrario. Por ejemplo,

``` ordenadaCiclicamente [1,2,3,4] == Just 0 ordenadaCiclicamente [5,8,1,3] == Just 2 ordenadaCiclicamente [4,6,7,5,1,3] == Nothing ordenadaCiclicamente [1,0,3,2] == Nothing ordenadaCiclicamente [1,2,0] == Just 2 ordenadaCiclicamente "cdeab" == Just 3```

Nota: Se supone que el argumento es una lista no vacía sin elementos repetidos.

#### Soluciones

```module Ordenada_ciclicamente where   import Test.QuickCheck (Arbitrary, Gen, NonEmptyList (NonEmpty), Property, arbitrary, chooseInt, collect, quickCheck) import Data.List (nub, sort) import Data.Maybe (isJust, listToMaybe)   -- 1ª solución -- ===========   ordenadaCiclicamente1 :: Ord a => [a] -> Maybe Int ordenadaCiclicamente1 xs = aux 0 xs where n = length xs aux i zs | i == n = Nothing | ordenada zs = Just i | otherwise = aux (i+1) (siguienteCiclo zs)   -- (ordenada xs) se verifica si la lista xs está ordenada -- crecientemente. Por ejemplo, -- ordenada "acd" == True -- ordenada "acdb" == False ordenada :: Ord a => [a] -> Bool ordenada [] = True ordenada (x:xs) = all (x <) xs && ordenada xs   -- (siguienteCiclo xs) es la lista obtenida añadiendo el primer elemento -- de xs al final del resto de xs. Por ejemplo, -- siguienteCiclo [3,2,5] => [2,5,3] siguienteCiclo :: [a] -> [a] siguienteCiclo [] = [] siguienteCiclo (x:xs) = xs ++ [x]   -- 2ª solución -- ===========   ordenadaCiclicamente2 :: Ord a => [a] -> Maybe Int ordenadaCiclicamente2 xs = listToMaybe [n | n <- [0..length xs-1], ordenada (drop n xs ++ take n xs)]   -- 3ª solución -- ===========   ordenadaCiclicamente3 :: Ord a => [a] -> Maybe Int ordenadaCiclicamente3 xs | ordenada (bs ++ as) = Just k | otherwise = Nothing where (_,k) = minimum (zip xs [0..]) (as,bs) = splitAt k xs   -- Comprobación de equivalencia -- ============================   -- La propiedad es prop_ordenadaCiclicamente1 :: NonEmptyList Int -> Bool prop_ordenadaCiclicamente1 (NonEmpty xs) = ordenadaCiclicamente1 xs == ordenadaCiclicamente2 xs   -- La comprobación es -- λ> quickCheck prop_ordenadaCiclicamente1 -- +++ OK, passed 100 tests.   -- La propiedad para analizar los casos de prueba prop_ordenadaCiclicamente2 :: NonEmptyList Int -> Property prop_ordenadaCiclicamente2 (NonEmpty xs) = collect (isJust (ordenadaCiclicamente1 xs)) \$ ordenadaCiclicamente1 xs == ordenadaCiclicamente2 xs   -- El análisis es -- λ> quickCheck prop_ordenadaCiclicamente2 -- +++ OK, passed 100 tests: -- 89% False -- 11% True   -- Tipo para generar listas newtype Lista = L [Int] deriving Show   -- Generador de listas. listaArbitraria :: Gen Lista listaArbitraria = do x <- arbitrary xs <- arbitrary let ys = x : xs k <- chooseInt (0, length ys) let (as,bs) = splitAt k (sort (nub ys)) return (L (bs ++ as))   -- Lista es una subclase de Arbitrary. instance Arbitrary Lista where arbitrary = listaArbitraria   -- La propiedad para analizar los casos de prueba prop_ordenadaCiclicamente3 :: Lista -> Property prop_ordenadaCiclicamente3 (L xs) = collect (isJust (ordenadaCiclicamente1 xs)) \$ ordenadaCiclicamente1 xs == ordenadaCiclicamente2 xs   -- El análisis es -- λ> quickCheck prop_ordenadaCiclicamente3 -- +++ OK, passed 100 tests (100% True).   -- Tipo para generar newtype Lista2 = L2 [Int] deriving Show   -- Generador de listas listaArbitraria2 :: Gen Lista2 listaArbitraria2 = do x' <- arbitrary xs <- arbitrary let ys = x' : xs k <- chooseInt (0, length ys) let (as,bs) = splitAt k (sort (nub ys)) n <- chooseInt (0,1) return (if even n then L2 (bs ++ as) else L2 ys)   -- Lista es una subclase de Arbitrary. instance Arbitrary Lista2 where arbitrary = listaArbitraria2   -- La propiedad para analizar los casos de prueba prop_ordenadaCiclicamente4 :: Lista2 -> Property prop_ordenadaCiclicamente4 (L2 xs) = collect (isJust (ordenadaCiclicamente1 xs)) \$ ordenadaCiclicamente1 xs == ordenadaCiclicamente2 xs   -- El análisis es -- λ> quickCheck prop_ordenadaCiclicamente4 -- +++ OK, passed 100 tests: -- 51% True -- 49% False   -- La propiedad es prop_ordenadaCiclicamente :: Lista2 -> Bool prop_ordenadaCiclicamente (L2 xs) = all (== ordenadaCiclicamente1 xs) [ordenadaCiclicamente2 xs, ordenadaCiclicamente3 xs]   -- La comprobación es -- λ> quickCheck prop_ordenadaCiclicamente -- +++ OK, passed 100 tests.   -- Comparación de eficiencia -- =========================   -- La comparación es -- λ> ordenadaCiclicamente1 ([100..4000] ++ [1..99]) -- Just 3901 -- (3.27 secs, 2,138,864,568 bytes) -- λ> ordenadaCiclicamente2 ([100..4000] ++ [1..99]) -- Just 3901 -- (2.44 secs, 1,430,040,008 bytes) -- λ> ordenadaCiclicamente3 ([100..4000] ++ [1..99]) -- Just 3901 -- (1.18 secs, 515,549,200 bytes)```

El código se encuentra en GitHub.

La elaboración de las soluciones se describe en el siguiente vídeo

#### Nuevas soluciones

• En los comentarios se pueden escribir nuevas soluciones.
• El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>

## Eliminación de las ocurrencias aisladas.

Definir la función

` eliminaAisladas :: Eq a => a -> [a] -> [a]`

tal que `(eliminaAisladas x ys)` es la lista obtenida eliminando en `ys` las ocurrencias aisladas de `x` (es decir, aquellas ocurrencias de `x` tales que su elemento anterior y posterior son distintos de `x`). Por ejemplo,

``` eliminaAisladas 'X' "" == "" eliminaAisladas 'X' "X" == "" eliminaAisladas 'X' "XX" == "XX" eliminaAisladas 'X' "XXX" == "XXX" eliminaAisladas 'X' "abcd" == "abcd" eliminaAisladas 'X' "Xabcd" == "abcd" eliminaAisladas 'X' "XXabcd" == "XXabcd" eliminaAisladas 'X' "XXXabcd" == "XXXabcd" eliminaAisladas 'X' "abcdX" == "abcd" eliminaAisladas 'X' "abcdXX" == "abcdXX" eliminaAisladas 'X' "abcdXXX" == "abcdXXX" eliminaAisladas 'X' "abXcd" == "abcd" eliminaAisladas 'X' "abXXcd" == "abXXcd" eliminaAisladas 'X' "abXXXcd" == "abXXXcd" eliminaAisladas 'X' "XabXcdX" == "abcd" eliminaAisladas 'X' "XXabXXcdXX" == "XXabXXcdXX" eliminaAisladas 'X' "XXXabXXXcdXXX" == "XXXabXXXcdXXX" eliminaAisladas 'X' "XabXXcdXeXXXfXx" == "abXXcdeXXXfx"```

#### Soluciones

```module Elimina_aisladas where   import Data.List (group) import Test.QuickCheck   -- 1ª solución -- ===========   eliminaAisladas1 :: Eq a => a -> [a] -> [a] eliminaAisladas1 _ [] = [] eliminaAisladas1 x [y] | x == y = [] | otherwise = [y] eliminaAisladas1 x (y1:y2:ys) | y1 /= x = y1 : eliminaAisladas1 x (y2:ys) | y2 /= x = y2 : eliminaAisladas1 x ys | otherwise = takeWhile (==x) (y1:y2:ys) ++ eliminaAisladas1 x (dropWhile (==x) ys)   -- 2ª solución -- ===========   eliminaAisladas2 :: Eq a => a -> [a] -> [a] eliminaAisladas2 _ [] = [] eliminaAisladas2 x ys | cs == [x] = as ++ eliminaAisladas2 x ds | otherwise = as ++ cs ++ eliminaAisladas2 x ds where (as,bs) = span (/=x) ys (cs,ds) = span (==x) bs   -- 3ª solución -- ===========   eliminaAisladas3 :: Eq a => a -> [a] -> [a] eliminaAisladas3 x ys = concat [zs | zs <- group ys, zs /= [x]]   -- 4ª solución -- ===========   eliminaAisladas4 :: Eq a => a -> [a] -> [a] eliminaAisladas4 x = concat . filter (/= [x]) . group     -- Comprobación de equivalencia -- ============================   -- La propiedad es prop_eliminaAisladas :: Int -> [Int] -> Bool prop_eliminaAisladas x ys = all (== eliminaAisladas1 x ys) [eliminaAisladas2 x ys, eliminaAisladas3 x ys, eliminaAisladas4 x ys]   -- La comprobación es -- λ> quickCheck prop_eliminaAisladas -- +++ OK, passed 100 tests.   -- Comparación de eficiencia -- =========================   -- La comparación es -- λ> length (eliminaAisladas1 'a' (take (5*10^6) (cycle "abca"))) -- 4999998 -- (3.86 secs, 2,030,515,400 bytes) -- λ> length (eliminaAisladas2 'a' (take (5*10^6) (cycle "abca"))) -- 4999998 -- (3.41 secs, 2,210,516,832 bytes) -- λ> length (eliminaAisladas3 'a' (take (5*10^6) (cycle "abca"))) -- 4999998 -- (2.11 secs, 2,280,516,448 bytes) -- λ> length (eliminaAisladas4 'a' (take (5*10^6) (cycle "abca"))) -- 4999998 -- (0.92 secs, 1,920,516,704 bytes)```

El código se encuentra en GitHub.

La elaboración de las soluciones se describe en el siguiente vídeo

#### Nuevas soluciones

• En los comentarios se pueden escribir nuevas soluciones.
• El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>

## Separación por posición

Definir la función

` particion :: [a] -> ([a],[a])`

tal que `(particion xs)` es el par cuya primera componente son los elementos de `xs` en posiciones pares y su segunda componente son los restantes elementos. Por ejemplo,

``` particion [3,5,6,2] == ([3,6],[5,2]) particion [3,5,6,2,7] == ([3,6,7],[5,2]) particion "particion" == ("priin","atco")```

#### Soluciones

```module Separacion_por_posicion where   import Data.List (partition) import qualified Data.Vector as V ((!), fromList, length) import Test.QuickCheck (quickCheck)   -- 1ª solución -- ===========   particion1 :: [a] -> ([a],[a]) particion1 xs = ([x | (n,x) <- nxs, even n], [x | (n,x) <- nxs, odd n]) where nxs = enumeracion xs   --(numeracion xs) es la enumeración de xs. Por ejemplo, -- enumeracion [7,9,6,8] == [(0,7),(1,9),(2,6),(3,8)] enumeracion :: [a] -> [(Int,a)] enumeracion = zip [0..]   -- 2ª solución -- ===========   particion2 :: [a] -> ([a],[a]) particion2 [] = ([],[]) particion2 (x:xs) = (x:zs,ys) where (ys,zs) = particion2 xs   -- 3ª solución -- ===========   particion3 :: [a] -> ([a],[a]) particion3 = foldr f ([],[]) where f x (ys,zs) = (x:zs,ys)   -- 4ª solución -- ===========   particion4 :: [a] -> ([a],[a]) particion4 = foldr (\x (ys,zs) -> (x:zs,ys)) ([],[])   -- 5ª solución -- ===========   particion5 :: [a] -> ([a],[a]) particion5 xs = ([xs!!k | k <- [0,2..n]], [xs!!k | k <- [1,3..n]]) where n = length xs - 1   -- 6ª solución -- ===========   particion6 :: [a] -> ([a],[a]) particion6 xs = (pares xs, impares xs)   -- (pares xs) es la lista de los elementos de xs en posiciones -- pares. Por ejemplo, -- pares [3,5,6,2] == [3,6] pares :: [a] -> [a] pares [] = [] pares (x:xs) = x : impares xs   -- (impares xs) es la lista de los elementos de xs en posiciones -- impares. Por ejemplo, -- impares [3,5,6,2] == [5,2] impares :: [a] -> [a] impares [] = [] impares (_:xs) = pares xs   -- 7ª solución -- ===========   particion7 :: [a] -> ([a],[a]) particion7 [] = ([],[]) particion7 xs = ([v V.! k | k <- [0,2..n-1]], [v V.! k | k <- [1,3..n-1]]) where v = V.fromList xs n = V.length v   -- 8ª solución -- ===========   particion8 :: [a] -> ([a],[a]) particion8 xs = (map snd ys, map snd zs) where (ys,zs) = partition posicionPar (zip [0..] xs)   posicionPar :: (Int,a) -> Bool posicionPar = even . fst   -- Comprobación de equivalencia -- ============================   -- La propiedad es prop_particion :: [Int] -> Bool prop_particion xs = all (== particion1 xs) [particion2 xs, particion3 xs, particion4 xs, particion5 xs, particion6 xs, particion7 xs, particion8 xs]   -- La comprobación es -- λ> quickCheck prop_particion -- +++ OK, passed 100 tests.   -- Comparación de eficiencia -- =========================   -- La comparación es -- λ> last (snd (particion1 [1..6*10^6])) -- 6000000 -- (2.74 secs, 2,184,516,080 bytes) -- λ> last (snd (particion2 [1..6*10^6])) -- 6000000 -- (2.02 secs, 1,992,515,880 bytes) -- λ> last (snd (particion3 [1..6*10^6])) -- 6000000 -- (3.17 secs, 1,767,423,240 bytes) -- λ> last (snd (particion4 [1..6*10^6])) -- 6000000 -- (3.23 secs, 1,767,423,240 bytes) -- λ> last (snd (particion5 [1..6*10^6])) -- 6000000 -- (1.62 secs, 1,032,516,192 bytes) -- λ> last (snd (particion5 [1..6*10^6])) -- 6000000 -- (1.33 secs, 1,032,516,192 bytes) -- λ> last (snd (particion6 [1..6*10^6])) -- 6000000 -- (1.80 secs, 888,515,960 bytes) -- λ> last (snd (particion7 [1..6*10^6])) -- 6000000 -- (1.29 secs, 1,166,865,672 bytes) -- λ> last (snd (particion8 [1..6*10^6])) -- 6000000 -- (0.87 secs, 3,384,516,616 bytes) -- -- λ> last (snd (particion5 [1..10^7])) -- 10000000 -- (1.94 secs, 1,720,516,872 bytes) -- λ> last (snd (particion7 [1..10^7])) -- 10000000 -- (2.54 secs, 1,989,215,176 bytes) -- λ> last (snd (particion8 [1..10^7])) -- 10000000 -- (1.33 secs, 5,640,516,960 bytes)```

El código se encuentra en GitHub.

La elaboración de las soluciones se describe en el siguiente vídeo

#### Nuevas soluciones

• En los comentarios se pueden escribir nuevas soluciones.
• El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>