Ejercicio Haskell números felices

Un número feliz es un entero positivo n que verifica la siguiente про-Пьедад: se reemplaza n por la suma de los cuadrados de sus dígitos y se repite el proceso имеет к obtener ООН 1. Por ejemplo, el 7 es feliz porque:

• 7 → 7^2 = 49

• 49 → 4^2 + 9^2 = 16 + 81 = 97

• 97 → 9^2 + 7^2 = 81 + 49 = 130

• 130 → 1^2 + 3^2 + 0^2 = 1 + 9 + 0 = 10

• 10 → 1^2 + 0^2 = 1 + 0 = 1

Un número que no es feliz es infeliz. En tal caso, el proceso предшествующие полости en bucle. Por ejemplo, полости es infeliz porque el proceso en bucle el 4 (aunque el bucle никакой tiene por qué presentarse en el primer elemento de la secuencia ESTO ÚLTIMO ES IMPORTANTE):

• 4 → 4^2 = 16

• 16 → 1^2 + 6^2 = 1 + 36 = 37

• 37 → 3^2 + 7^2 = 9 + 49 = 58

• 58 → 5^2 + 8^2 = 25 + 64 = 89

• 89 → 8^2 + 9^2 = 64 + 81 = 145

• 145 → 1^2 + 4^2 + 5^2 = 1 + 16 + 25 = 42

• 42 → 4^2 + 2^2 = 16 + 4 = 20

• 20 → 2^2 + 0^2 = 4 + 0 = 4

Определите una función digitosDe :: Integer -> [Integer] que облицовывают панелями ООН естественная devuelva ООН, Листа подставляет sus dígitos:

digitosDe :: Integer -> [Integer]
digitosDe x  = reverse (digitosDe' x)
    where digitosDe' x 
            |x < 10 = [x]
            |otherwise = (x `mod` 10) : digitosDe' (x`div`10)

Определите una función sumaCuadradosDigitos :: Integer -> Integer que облицовывают панелями un naturaldevuelva la suma de los cuadrados de sus dígitos:

sumaCuadradosDigitos :: Integer -> Integer
sumaCuadradosDigitos x = sum (map (^2) (digitosDe x))  

Определите una función esFeliz :: Integer -> Bool que определяют СИ ООН entero positivo es feliz:

esFeliz :: Integer -> Bool
esFeliz x 
    |sumaCuadradosDigitos x == 1 = True
    |otherwise = esFeliz (sumaCuadradosDigitos x)

HE AQUÍ EL PROBLEMA: никакой sé cómo пара el bucle en el caso que se detecte que existe

Se я sugiere usar una funcion auxiliar"esFelizAc"que используют довод "против" recursión фургон acumulador y emplear éste para almacenar los números que se obteniendo en la sucesivas iteraciones.

2
задан 04.11.2019, 10:40
1 ответ

Договора. Давайте начинаться с немного teorГ - в. Давайте предполагать, что мы хотим сделать следующую funciГіn:

unfold :: a -> [b]

Как предложи имя, unfold делает ее operaciГіn обратная из fold и сходные:

fold :: [a] -> b

(Он замечает: типа fold serГ-an sum, product, head, last... foldr, foldl...)

мы Можем осуществлять unfold посредством recursiГіn применяя iterativamente одна funciГіn f для того, чтобы он дал элементы в команде: Этой definiciГіn не хватает

unfold :: a -> [b]
unfold x = y : unfold z
  where (y,z) = f x

она condiciГіn остановки, чтобы предотвращать одна recursiГіn бесконечная . То, что возможно оценивать, состоит в том, что он является совсем не работоспособным: у себя требует, чтобы получить оставшуюся часть списка перед тем, как мочь aГ±adir элемент, что будет нуждаться в достаточном количестве памяти, чтобы сохранять промежуточные результаты до конца ее operaciГіn.

Давайте Вводить аккумулятор:

unfold :: a -> [b]
unfold = unfoldAc []

unfoldAc :: [b] -> a -> [b]
unfoldAc xs x | cond x    = xs
              | otherwise = unfoldAc (y:xs) z
  where (y,z) = f x

В первом аргументе xs из unfoldAc идет аккумулятор. Начнись vacГ - или и он наполняется произведенными элементами. Когда будет выполнена она condiciГіn cond, для нее recursiГіn, и возврати то, что есть в аккумуляторе. Хорошее этой implementaciГіn состоит в том, что его не требуют, сохранять ningГєn промежуточный результат, так как все проходит как аргумент. Вот то, что известно как "optimizaciГіn tailrec " .

Давайте Видеть cГіmo изменять ты implementaciГіn digitosDe помещая аккумулятор:

digitosDe :: Integer -> [Integer]
digitosDe = digitosDe' []
 where
  digitosDeAc xs x | x < 10    = x : xs
                   | otherwise = digitosDeAc (m : xs) d
    where (d, m) = x `divMod` 10

Как видно, уходят накапливая числа, которые он вычисляет, и в порядке, который мы хотим (сначала он помещает в аккумулятор единицы, потом десятки, и т.д., и т.д.).

В любом случае, есть одна implementaciГіn mГЎs прямая (хотя менее элегантный) используя их mГ©todos чтения / написания haskell:

digitosDe :: Integer -> [Integer]
digitosDe x = [ read [c] | c <- show x ]

, Но давайте идти в случай, который занимает нас, cГіmo помещать аккумулятор в ней funciГіn esFeliz:

esFeliz :: Integer -> Bool
esFeliz = esFelizAc []
 where
  esFelizAc xs x | x `elem` xs = False
                 | s == 1      = True
                 | otherwise   = esFelizAc (x : xs) s
    where s = sumaCuadradosDigitos x

Аккумулятор мы это используем, чтобы помещать те nГєmeros, который уже мы увидели. Если nГєmero, чтобы подтверждать уже, он был виден, возврати False ( неудачник ). Если суммы квадратов 1, возврати True (счастливые ). Если ни одна ни другая вещь, тогда он это не помещает в аккумулятор и вновь начинается, этот раз с суммой квадратов.

Вещь, которую нужно иметь в виду, состоит в том, что весь они nГєmeros аккумулятора они nГєmeros счастливые или несчастные, segГєn был концом последовательности. Если он шел использовать много эту funciГіn, podrГ - создавать список nГєmeros счастливые и другая из неудачников, и идти llenГЎndola с ними nГєmeros, что виделись. Или же, одна funciГіn с тремя аккумуляторами. Но я это оставляю aquГ - потому что я не хочу осложнить mГЎs ответ.

1
ответ дан 01.12.2019, 12:56