将整数分解为数字列表

Break an integer to a list of digits

我正在学习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 函数?

怎么样:

digits n = fmap digitToInt $ show n

我忘了提到您需要先从 Data.Char 导入 digitToInt,如@bheklilr 的回答。

使用@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

我的计时发现它更快并且在未优化的 GHCi 会话中使用了大约 25% 的内存,它也不会颠倒数字的顺序。

首先,写带有守卫的代码总是比 if-then-else 更具可读性。所有无关的括号也让人分心。

低效 appending-at-end 函数的标准转换,例如您的

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)

--                            [a,b,c,...,x,y]         [z]
--                            [a,b,c,...,x]         [y,z]

因此,以相反顺序生成的数字一个一个地进入累加器参数中从下到上构建的结果列表,从而以正确的顺序创建列表。