【问题标题】:Cant figure out simple haskell recursion problem无法弄清楚简单的haskell递归问题
【发布时间】:2019-09-17 23:51:06
【问题描述】:

我正在尝试编写一个简单的haskell 程序来总结一个整数的数字,例如我的整数是888,所以总和应该是8+8+8=24。我把这部分记下来了,但我希望我的程序继续运行,直到没有什么要添加,例如在添加 8+8+8 = 24 之后它应该添加 2 + 4 = 6 然后返回 6。感谢您的帮助!

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)

【问题讨论】:

    标签: haskell recursion functional-programming


    【解决方案1】:

    一个正数和它的数字总和总是以 9 为模全等的。此外,由于所有非零数都至少有一个正数而没有负数,所以没有办法从一个正数中得到一个数字和 0。因此:

    digitSum x = case (x, x `mod` 9) of
        (0, _) -> 0
        (_, 0) -> 9
        (_, v) -> v
    

    在 ghci 中尝试一下:

    > digitSum 888
    6
    

    这个函数在负数上可能无法达到你的预期——但是,原来的函数也不能优雅地处理负数,所以...... =)

    【讨论】:

      【解决方案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
      

      【讨论】:

      • 感谢您的帮助!我现在明白了一点。但是代码编译还有另一个问题,但是当我运行它时,程序挂起而没有任何输出
      • 谢谢,不幸的是我现在无法调试它,听起来好像有一个无限递归。当我提出解决方案时会通知您。 (也很乐意接受画廊的建议 :))
      • 好的,手工完成它我已经弄清楚为什么它处于无限循环中。我忘了我也需要firstResult 中的非递归案例!将立即编辑以添加此内容。 (其实在这样做的过程中我已经意识到有更大的问题。再次道歉,让我完全重写这个......)
      • 对,为此道歉,原来我的主要错误只是在进行递归调用之前忘记对列表求和。我很尴尬,请尝试新版本,如果出现任何问题,请告诉我。
      【解决方案3】:

      在替代答案中,特别是因为您正在执行递归数字(以 10 为基数)求和并且默认 show 实例以 10 为基数,您可以通过字符串往返并用视图模式很好地编写,

      {-# LANGUAGE ViewPatterns #-}
      
      digitSum :: Int -> Int
      digitSum x@(show -> (_:"")) = x
      digitSum (show -> cs) = digitSum $ sum . map ( read . (:[]) ) $ cs
      

      如果字符串表示是任何单个字符(即0 &lt;= x &lt;= 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 
      

      【讨论】:

        猜你喜欢
        • 2015-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-03
        相关资源
        最近更新 更多