无法解决简单的haskell递归问题

时间:2019-04-29 10:58:52

标签: haskell recursion functional-programming

我正在尝试编写一个简单的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)

3 个答案:

答案 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