Reputation: 13692
I am learning Haskell, and I am solving 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]
Is there a more readable way to implement the digits
function ?
Upvotes: 1
Views: 1028
Reputation: 71065
First of all it is always more readable to write code with guards, instead of if-then-else
. All the extraneous parens are also distracting.
The standard transformation for the inefficient appending-at-end functions, like your
digits n | n < 10 = [n]
| otherwise = digits (quot n 10) ++ [mod n 10]
is to introduce an additional argument, where calling the old digits n ++ xs
is the same as calling the new 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)
-- [a,b,c,...,x,y] [z]
-- [a,b,c,...,x] [y,z]
Thus the digits being produced in the reversed order go one by one into the result list being built bottom-to-the-top in an accumulator parameter, resulting in the list created in the correct order.
Upvotes: 2
Reputation: 5459
What about:
digits n = fmap digitToInt $ show n
I forgot to mention that you need to import digitToInt
from Data.Char
first, as in @bheklilr's answer.
Upvotes: 3
Reputation: 54058
Using @BenjaminHodgson's suggestion, you can write an unfold
as
import Data.Tuple (swap)
import Data.List (unfoldr)
digits = unfoldr go
where go 0 = Nothing
go n = Just (swap $ n `divMod` 10)
However, due to how unfoldr
works you will get the digits in reverse order here. Another solution is to ditch this entirely and go with
import Data.Char (digitToInt)
digits = map digitToInt . show
My timings found it to be faster and use about 25% of the memory in an unoptimized GHCi session, it also doesn't reverse the order of the digits.
Upvotes: 2