Enumeración de los números enteros
Definir la sucesión
enteros :: [Int]
tal que sus elementos son los números enteros comenzando en el 0 e intercalando los positivos y los negativos. Por ejemplo,
λ> take 23 enteros [0,1,-1,2,-2,3,-3,4,-4,5,-5,6,-6,7,-7,8,-8,9,-9,10,-10,11,-11] λ> enteros !! (3*10^7) -15000000
Comprobar con QuickCheck que el n-ésimo término de la sucesión es \(\frac{1-(2n+1)(-1)^n}{4}\).
Soluciones
import Data.List (transpose) import Control.Applicative ((<**>)) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1ª solución -- =========== enteros1 :: [Int] enteros1 = 0 : concat [[n,-n] | n <- [1..]] -- 2ª solución -- =========== enteros2 :: [Int] enteros2 = 0 : [y | x <- [1..], y <- [x, -x]] -- 3ª solución -- =========== enteros3 :: [Int] enteros3 = 0 : concatMap (\n -> [n, -n]) [1..] -- 4ª solución -- =========== enteros4 :: [Int] enteros4 = 0 : mezcla [1..] [-1, -2..] where mezcla (x:xs) ys = x : mezcla ys xs -- 5ª solución -- ============ enteros5 :: [Int] enteros5 = 0 : concat (transpose [[1..], [-1, -2..]]) -- 6ª solución -- =========== enteros6 :: [Int] enteros6 = iterate siguiente 0 where siguiente i | i > 0 = -i | otherwise = 1 - i -- 7ª solución -- =========== enteros7 :: [Int] enteros7 = iterate (\i -> if i > 0 then -i else 1-i) 0 -- 8ª solución -- =========== enteros8 :: [Int] enteros8 = 0 : ([1..] <**> [id, negate]) -- 9ª solución -- ============ enteros9 :: [Int] enteros9 = scanl (+) 0 (zipWith (*) [1..] (cycle [1, -1])) -- 10ª solución -- ============ enteros10 :: [Int] enteros10 = 0 : [f x | x <- [1..], f <- [id, negate]] -- 11ª solución -- ============ enteros11 :: [Int] enteros11 = map transforma [0..] where transforma n | n == 0 = 0 | odd n = (n + 1) `div` 2 | otherwise = -(n `div` 2) -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: [Int] -> Spec specG enteros = do it "e1" $ take 23 enteros `shouldBe` [0,1,-1,2,-2,3,-3,4,-4,5,-5,6,-6,7,-7,8,-8,9,-9,10,-10,11,-11] spec :: Spec spec = do describe "def. 1" $ specG enteros1 describe "def. 2" $ specG enteros2 describe "def. 3" $ specG enteros3 describe "def. 4" $ specG enteros4 describe "def. 5" $ specG enteros5 describe "def. 6" $ specG enteros6 describe "def. 7" $ specG enteros7 describe "def. 8" $ specG enteros8 describe "def. 9" $ specG enteros9 describe "def. 10" $ specG enteros10 describe "def. 11" $ specG enteros11 -- La verificación es -- λ> verifica -- 6 examples, 0 failures -- Comprobación de equivalencia -- ============================ -- -- La propiedad es prop_equivalencia :: NonNegative Int -> Bool prop_equivalencia (NonNegative n) = all (== enteros1 !! n) [enteros2 !! n, enteros3 !! n, enteros4 !! n, enteros5 !! n, enteros6 !! n, enteros7 !! n, enteros8 !! n, enteros9 !! n, enteros10 !! n, enteros11 !! n] -- La comprobación es -- λ> quickCheckWith (stdArgs {maxSize=7}) prop_equivalencia -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> :set +s -- λ> enteros1 !! (5*10^6) -- -2500000 -- (1.26 secs, 980,597,792 bytes) -- λ> enteros2 !! (5*10^6) -- -2500000 -- (1.79 secs, 1,020,597,592 bytes) -- λ> enteros3 !! (5*10^6) -- -2500000 -- (0.57 secs, 800,598,560 bytes) -- λ> enteros4 !! (5*10^6) -- -2500000 -- (1.97 secs, 1,020,597,576 bytes) -- λ> enteros5 !! (5*10^6) -- -2500000 -- (0.75 secs, 1,480,595,552 bytes) -- λ> enteros6 !! (5*10^6) -- -2500000 -- (5.13 secs, 2,042,951,592 bytes) -- λ> enteros7 !! (5*10^6) -- -2500000 -- (4.10 secs, 1,318,970,024 bytes) -- λ> enteros8 !! (5*10^6) -- -2500000 -- (0.46 secs, 820,598,472 bytes) -- λ> enteros9 !! (5*10^6) -- -2500000 -- (2.25 secs, 1,726,728,960 bytes) -- λ> enteros10 !! (5*10^6) -- -2500000 -- (3.09 secs, 1,240,596,624 bytes) -- λ> enteros11 !! (5*10^6) -- -2500000 -- (0.12 secs, 800,599,232 bytes) -- -- λ> enteros3 !! (10^7) -- -5000000 -- (1.85 secs, 1,600,602,280 bytes) -- λ> enteros5 !! (10^7) -- -5000000 -- (0.84 secs, 2,960,602,480 bytes) -- λ> enteros8 !! (10^7) -- -5000000 -- (0.65 secs, 1,640,602,368 bytes) -- λ> enteros11 !! (10^7) -- -5000000 -- (0.49 secs, 1,600,605,592 bytes) -- -- λ> enteros5 !! (3*10^7) -- -15000000 -- (3.36 secs, 8,880,603,304 bytes) -- λ> enteros8 !! (3*10^7) -- -15000000 -- (3.28 secs, 4,920,603,200 bytes) -- λ> enteros11 !! (3*10^7) -- -15000000 -- (2.84 secs, 4,800,606,416 bytes) -- Propiedad -- ========= -- La propiedad es prop_enteros :: Positive Int -> Bool prop_enteros (Positive n) = enteros1 !! n == (1-(2*n+1)*(-1)^n) `div` 4 -- La comprobación es -- λ> quickCheckWith (stdArgs {maxSize=7}) prop_enteros -- +++ OK, passed 100 tests.