我正在尝试编写一个简单的haskell程序,该程序将一个整数加起来,例如我的整数是888,所以总和应该是8 + 8 + 8 = 24。我把这部分讲完了,但是我希望我的程序继续运行,直到没有什么可添加的为止,例如,在添加8 + 8 + 8 = 24之后,它应该添加2 + 4 = 6,然后返回6。 / p>
import System.IO
import Data.List
integer = 888
todigits :: Integral x => x -> [x]
todigits 0 = []
todigits x = todigits (x `div` 10) ++ [x `mod` 10]
add::[Int]->Int
add (x:xs) = sum(x:xs)
added = add (todigits integer)
main = do
print(added)
答案 0 :(得分:3)
一个正数及其数字总和总是取9的模。此外,由于所有非零数字都至少具有一个正数且没有负数,因此无法从正数中获取数字总和0。因此:
digitSum x = case (x, x `mod` 9) of
(0, _) -> 0
(_, 0) -> 9
(_, v) -> v
在ghci中试用:
> digitSum 888
6
此功能可能无法满足您对负数的期望-但是,原始函数也无法正常处理负数,因此... =)
答案 1 :(得分:2)
您的函数只适用一次迭代。您只需要递归调用它,直到得到一个1位数字的结果(或者,当然是一个空列表)。
我们将从您现有的功能开始,我已经对其进行了重命名和重写,以便它以相反的顺序返回列表(单位数字在前)。这根本没有必要,您可以使用先前的定义(因为到目前为止,我们唯一感兴趣的是列表的总和,顺序无关紧要),但这会更多如果您需要从数字列表中重建数字(并且我认为应该做得更好),也很方便:
todigitsOnce :: Integral x => x -> [x]
todigitsOnce 0 = []
todigitsOnce x = x `mod` 10 : todigitsOnce (x `div` 10)
这是递归toDigit
函数:
toDigit :: Integral x => x -> [x]
toDigit x
| length firstResult < 2 = firstResult
| otherwise = toDigit . sum $ firstResult
where firstResult = todigitsOnce x
答案 2 :(得分:2)
在另一个答案中,尤其是因为您要进行递归数字(以10为底)的求和,而默认的show
实例是以10为底,您可以通过字符串来回往返并很好地用视图模式书写,>
{-# LANGUAGE ViewPatterns #-}
digitSum :: Int -> Int
digitSum x@(show -> (_:"")) = x
digitSum (show -> cs) = digitSum $ sum . map ( read . (:[]) ) $ cs
如果字符串表示形式是任何单个字符(即0 <= x <= 9
),则只需返回x
,否则就以字符串表示形式中的整数之和递归。
您仍然可以很好地使用视图模式(imo),而无需进行往返操作,但是它确实需要辅助功能来将整数表示为其数字列表,
import Data.List (unfoldr)
import Data.Tuple (swap)
digitList :: (Integral a) => a -> [a]
digitList 0 = [0]
digitList n = unfoldr f n
where f 0 = Nothing
f i = Just . swap $ i `divMod` 10
digitSum' :: (Integral a) => a -> a
digitSum' (digitList -> x:[]) = x
digitSum' (digitList -> xs) = digitSum' $ sum xs