这是编写Haskell foldr函数的正确方法吗?

时间:2009-05-16 05:11:57

标签: haskell fold combinators

我正在从YAHT's Recursive Datatype部分进行练习,发现编写listFoldr函数有点挑战(主要是因为我并不真正理解foldl和{{1}之间的区别}} 首先)。当我最终确切地意识到foldr函数是如何工作的时候,我决定将函数参数的简单交换作为将foldr函数更改为listFoldl函数所需的全部内容:

listFoldr

这似乎有效(我做了比这更多的测试):

listFoldl f i [] = i
listFoldl f i (x:xs) = listFoldl f (f i x) xs

listFoldr f i [] = i
listFoldr f i (x:xs) = listFoldr f (f x i) xs

但是练习的solution与我的大不相同。他们的Main> foldr (-) 4 [1, 2, 3] -2 Main> listFoldr (-) 4 [1, 2, 3] -2 与我的完全相同,但请查看他们的listFoldl

listFoldr

哪种解决方案更好,我的还是他们的?其中一个是不正确的? (在我的测试中,他们都得到了完全相同的结果......)

4 个答案:

答案 0 :(得分:5)

您的解决方案绝对不正确。您只需实现foldl,其中函数f以相反的顺序接受参数。例如,出现了什么问题,foldr (:) []应该是列表上的识别函数,但是您的函数会反转列表。您的函数不是foldr的原因还有很多其他原因,例如foldr如何在无限列表中工作而您的函数不在。{1}}。在你的例子中它们是相同的,这是纯粹的巧合,因为3 - (2 - (1 - 4)) == 1 - (2 - (3 - 4))。我认为你应该从头开始看看foldr应该如何运作。

答案 1 :(得分:4)

我认为你正在以“相反的顺序”处理元素,因此你的不对。

您应该能够通过“订单重要”的示例来证明这一点。例如,像

listfoldr f "" ["a", "b", "c"]

其中'f'是

行的函数
f s1 s2 = "now processing f(" @ s1 @ "," @ s2 @ ")\n"

其中'@'是一个字符串附加运算符(我忘记它在Haskell中的含义)。关键在于“检测”函数,以便您可以看到使用各种参数调用它的顺序。

(请注意,这并未出现在您的示例中,因为数学“4-1-2-3”产生与“4-3-2-1”相同的答案。)

答案 2 :(得分:4)

你的坏了。尝试使用不会产生单个数字结果的东西。

eg: listFoldr (++) "a" ["b", "c", "d"]

你的处理方向错误。

答案 3 :(得分:2)

在列表[x1, x2, ..., xk]上,您的listFoldr计算

 f xk (... (f x2 (f x1 i)) ...)

foldr应计算

 f x1 (f x2 (... (f xk i) ...))

(相比之下,foldl计算

f (... (f (f i x1) x2) ...) xk

基本上,listFoldr f = foldl (flip f)。)

你的测试用例很不幸,因为

3 - (2 - (1 - 4)) = 1 - (2  - (3 - 4))

当您测试这些函数时,请确保传入一个非交换和非关联的f(即参数和应用程序顺序问题),这样您就可以确定表达式已被评估正确。当然,减法是非交换性和非关联性的,你只是运气不好。