-- 1ª solución
-- ===========
autonumeros :: [Integer]
autonumeros = filter autonumero [1..]
-- (autonumero n) se verifica si n es un autonúmero. Por ejemplo,
-- autonumero 5 == True
-- autonumero 21 == False
autonumero :: Integer -> Bool
autonumero n =
all (/=n) [k + sum (digitos k) | k <- [1..n]]
-- (digitos n) es la lista de los dígitos de n. Por ejemplo,
-- digitos 325 == [3,2,5]
digitos :: Integer -> [Integer]
digitos a = [read [c] | c <-show a]
-- 2ª solución
-- ===========
autonumeros2 :: [Integer]
autonumeros2 = map head sucesionSucesionesSumasDigitales
-- sucesionSucesionesSumasDigitales es la lista de las sucesiones de
-- sumas parciales tal que el primer elemento de cada sucesión es el
-- menor elemento que no pertenece a las sucesiones anteriores. Por
-- ejemplo,
-- λ> map (take 4) (take 8 sucesionSucesionesSumasDigitales)
-- [[1,2,4,8],[3,6,12,15],[5,10,11,13],[7,14,19,29],
-- [9,18,27,36],[20,22,26,34],[31,35,43,50],[42,48,60,66]]
sucesionSucesionesSumasDigitales :: [[Integer]]
sucesionSucesionesSumasDigitales = aux [1..]
where aux xs = sucesion xs : aux (diferencia xs (sucesion xs))
sucesion xs = sucesionSumasDigitales (head xs)
-- (diferencia xs ys) es la diferencia las listas infinitas ordenadas
-- crecientes xs e ys. Por ejemplo,
-- λ> take 8 (diferencia [1..] [2,4..])
-- [1,3,5,7,9,11,13,15]
diferencia :: [Integer] -> [Integer] -> [Integer]
diferencia (x:xs) (y:ys)
| x == y = diferencia xs ys
| otherwise = x : diferencia xs (y:ys)
-- (sucesionSumasDigitales a) es la sucesión de las sumas digitales
-- definida por un número a. Por ejemplo,
-- λ> take 16 (sucesionSumasDigitales 1)
-- [1,2,4,8,16,23,28,38,49,62,70,77,91,101,103,107]
-- λ> take 16 (sucesionSumasDigitales 3)
-- [3,6,12,15,21,24,30,33,39,51,57,69,84,96,111,114]
-- λ> take 16 (sucesionSumasDigitales 5)
-- [5,10,11,13,17,25,32,37,47,58,71,79,95,109,119,130]
-- λ> take 16 (sucesionSumasDigitales 7)
-- [7,14,19,29,40,44,52,59,73,83,94,107,115,122,127,137]
-- λ> take 16 (sucesionSumasDigitales 9)
-- [9,18,27,36,45,54,63,72,81,90,99,117,126,135,144,153]
-- λ> take 16 (sucesionSumasDigitales 20)
-- [20,22,26,34,41,46,56,67,80,88,104,109,119,130,134,142]
sucesionSumasDigitales :: Integer -> [Integer]
sucesionSumasDigitales a =
iterate siguienteSumaDigital a
-- (siguienteSumaDigital a) es el siguiente de a en la sucesión de sumas
-- digitales. Por ejemplo,
-- siguienteSumaDigital 23 == 28
siguienteSumaDigital :: Integer -> Integer
siguienteSumaDigital a =
a + sum (digitos a)
-- Comparación de eficiencia
-- =========================
-- La comparación es
-- λ> autonumeros !! 150
-- 1502
-- (4.54 secs, 13,302,379,936 bytes)
-- λ> autonumeros2 !! 150
-- 1502
-- (0.06 secs, 41,794,872 bytes)