使用foldr在Haskell中定义函数

时间:2013-11-23 22:28:15

标签: haskell decimal fold digits

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

    fromDigits :: [Int] -> Int

此函数获取Ints列表(每个Ints范围从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..]))

但现在我必须使用折叠器来定义它,但我不知道如何获得10的能力。我拥有的是:

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

如何让它们减少?我知道我可以从(长xs - 1)开始但是那么呢?

最好的问候

3 个答案:

答案 0 :(得分:3)

关于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 -th列表元素用于{em> j 连续调用f。头元素仅传递一次到函数的左侧。对于您的应用程序,head元素是最后一位数字。这应该如何影响结果?好吧,它只是添加到结果中,不是吗?

15 = 10 + 5
623987236705839 = 623987236705830 + 9

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

现在应该给予足够的暗示。

答案 1 :(得分:3)

你快到了那里:

你的

  

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

是一个有两点变化的解决方案:

  

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

(顺便说一下,我在每一方都遗漏了xs,这是没有必要的。

另一种选择是

  

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

答案 2 :(得分:2)

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

(但你上面给出的列表已经是相反的顺序了,所以你可以说你应该能够重新反转它们,然后说你的函数以正确的顺序取一个数字列表。如果没有,那么只需要除以10而不是乘以10。)