【问题标题】:Define function in Haskell using foldr使用 foldr 在 Haskell 中定义函数
【发布时间】:2013-11-23 22:28:14
【问题描述】:

我正在尝试使用 foldr 函数在 Haskell 中定义一个函数:

    fromDigits :: [Int] -> Int

这个函数接受一个 Int 列表(每个从 0 到 9)并转换为单个 Int。例如:

    fromDigits [0,1] = 10
    fromDigits [4,3,2,1] = 1234
    fromDigits [2,3,9] = 932
    fromDigits [2,3,9,0,1] = 10932

无论如何,我使用显式递归甚至使用 zipWith 来定义它都没有问题:

    fromDigits n = sum (zipWith (*) n (map ((^)10) [0..]))

但现在我必须使用 foldr 来定义它,但我不知道如何获得 10 的幂。我所拥有的是:

    fromDigits xs = foldr (\x acc -> (x*10^(???)) + acc) 0 xs

我怎样才能让它们减少?我知道我可以从 (length xs - 1) 开始,但是然后呢?

最好的问候

【问题讨论】:

  • 你不能用foldr (+) 0替换sum吗? :)
  • 神秘提示:flip fmap (*10) `fmap` (+)
  • 在这种情况下看起来像左折叠会更自然。

标签: haskell decimal fold digits


【解决方案1】:

你快到了:

你的

fromDigits xs = foldr (\x acc -> (x*10^(???)) + acc) 0 xs

是有 2 个小变化的解决方案:

fromDigits = foldr (\x acc -> acc*10 + x) 0

(顺便说一句,我在两边都省略了xs,这没有必要。

另一种选择是

fromDigits = foldl (\x acc -> 读取 $ (show x) ++ (show acc)) 0

【讨论】:

  • 使用 foldl,参数相对于 foldr 翻转。
【解决方案2】:

foldr 的好处在于它非常容易可视化!

foldr f init [a,b, ... z]
≡ foldr f init $ a : b : ... z : []
≡                a`f b`f`... z`f`init
≡ f a (f b ( ... (f z init)...)))

如您所见,第 j 个列表元素用于 j 个连续调用 f。 head 元素仅在函数左侧传递一次。对于您的应用程序,头部元素是最后一个数字。这应该如何影响结果?好吧,它只是添加到结果中,不是吗?

15 = 10 + 5
623987236705839 = 623987236705830 + 9

——很明显。那么问题来了,你如何照顾其他数字?好吧,要使用上述技巧,您首先需要确保携带子结果的最后一个位置为 0。不是来自提供的数字的 0!这样的零怎么加?

现在给出的提示应该已经足够了。

【讨论】:

    【解决方案3】:

    诀窍是,您不需要每次都从头计算 10 的幂,您只需要根据之前的 10 的幂(即乘以 10)来计算它。好吧,假设您可以反转输入列表。

    (但是您在上面给出的列表已经是相反的顺序,所以可以说您应该能够重新反转它们并只是说您的函数以正确的顺序获取数字列表。如果不是,那么只需除以10 而不是乘以 10。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多