2016-11-03 6 views
0

Я изучаю Haskell, и я решаю problem 30 on project Euler.Перерыв целого числа на список цифр

digits n = if n<10 then [n] else (digits (quot n 10)) ++ [(mod n 10)] 
isP30 n = (sum $ map (^5) $ digits n) == n 
sum $ filter isP30 [10^5..10^6-1] 

Есть ли более читаемым способ реализации функции digits?

+1

Как насчет использования [разворачивания] (http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-List.html#v:unfoldr)? –

+0

@BenjaminHodgson, не могли бы вы рассказать? –

+1

'unfoldr' обобщает цикл, который создает элемент списка на каждом шаге. Все, что вам нужно сделать, это определить функцию, которая, учитывая текущее «состояние» цикла, принимает решение о прекращении создания значений списка («Nothing») или создании значения ('x') и повторении цикла с новым состоянием (' s ') (выполняется с помощью' Just (x, s) '. Например,' unfoldr (\ n -> if n == 10 then Nothing else Just (n, n + 1)) 0' будет выдавать '[0..9 ] '. Вы можете использовать это для создания своих цифр в обратном направлении и« обратного »их в конце. – chi

ответ

2

Используя @ предложение BenjaminHodgson, вы можете написать unfold в

import Data.Tuple (swap) 
import Data.List (unfoldr) 

digits = unfoldr go 
    where go 0 = Nothing 
      go n = Just (swap $ n `divMod` 10) 

Однако из-за того, как unfoldr работы вы получите цифры в обратном порядке здесь. Другим решением является канаву это полностью и идти с

import Data.Char (digitToInt) 

digits = map digitToInt . show 

Мои тайминги нашел, что это будет быстрее и использовать около 25% памяти в неоптимизированной сессии GHCi, он также не меняет порядок цифр.

3

насчет:

digits n = fmap digitToInt $ show n 

Я забыл упомянуть, что вам нужно импортировать digitToInt из Data.Char первых, как и в ответ @ bheklilr в.

1

Прежде всего, всегда более читаемо писать код с защитой, а не if-then-else. Все посторонние парны также отвлекают.

Стандартное преобразование для неэффективных Добавления данных-в-конце функций, как вашего

digits n | n < 10 = [n] 
     | otherwise = digits (quot n 10) ++ [mod n 10] 

является ввести дополнительный аргумент, где вызов старой digits n ++ xs такой же, как назвать новые go n xs:

digits n = go n [] -- digits_old n ++ [] == go n [] 
    where 
    go n next | n < 10 = n : next 
      | otherwise = go (quot n 10) (mod n 10 : next)