Ir al contenido principal

Repetición cíclica

Definir la función

ciclica :: [a] -> [a]

tal que (ciclica xs) es la lista obtenida repitiendo cíclicamente los elementos de xs. Por ejemplo,

take 10 (ciclica [3,5])    ==  [3,5,3,5,3,5,3,5,3,5]
take 10 (ciclica [3,5,7])  ==  [3,5,7,3,5,7,3,5,7,3]
take 10 (ciclica [3,5..])  ==  [3,5,7,9,11,13,15,17,19,1]
ciclica []                 ==  []

Comprobar con QuickCheck que la función ciclica es equivalente a la predefinida cycle; es decir, para cualquier número entero n y cualquier lista no vacía xs, se verifica que

take n (ciclica xs) == take n (cycle 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_ciclica
+++ OK, passed 100 tests.

Soluciones

import Test.QuickCheck

-- 1ª definición
ciclica1 :: [a] -> [a]
ciclica1 [] = []
ciclica1 xs = xs ++ ciclica1 xs

-- 2ª definición
ciclica2 :: [a] -> [a]
ciclica2 [] = []
ciclica2 xs = xs' where xs' = xs ++ xs'

-- Comprobación de eficiencia
--    λ> last (take 10000000 (ciclica1 [1,2]))
--    2
--    (3.69 secs, 1521758928 bytes)
--
--    λ> last (take 10000000 (ciclica2 [1,2]))
--    2
--    (0.21 secs, 561468144 bytes)
-- La 2ª definición es más eficiente.

-- La propiedad es
prop_ciclica :: Int -> [Int] -> Property
prop_ciclica n xs =
    not (null xs) ==>
    take n (ciclica2 xs) == take n (cycle xs)

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