foldl / foldr查询

我是Haskell的初学者,甚至在阅读了foldr / foldl的几个解释之后,我无法理解为什么我会在下面得到不同的结果。 什么是解释?

Prelude> foldl (_ -> (+1)) 0 [1,2,3]
4
Prelude> foldr (_ -> (+1)) 0 [1,2,3]
3

谢谢!


foldl情况下,lambda传递的是累加器作为第一个参数,而列表元素作为第二个参数。 在foldr情况下,lambda被作为第一个参数传递给list元素,第二个作为累加器。

你的lambda忽略了第一个参数,并在第二个参数中加1,所以在foldl情况下,你要为最后一个元素加1,在foldr情况下,你要计算列表中元素的数量。


这是因为参数的顺序在foldl翻转。 比较他们的类型签名:

foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b

所以你看到,在你的代码中使用foldl ,你会重复增加累加器,忽略列表。 但是在使用foldr的代码中,您甚至不会触摸累加器,只是增加列表的元素。 最后一个元素是3 ,结果是3 + 1 = 4

你可以看到你的错误更容易,如果你使用一个字符列表,也就是字符串:

ghci> foldr (_ -> (+1)) 0 ['a','b','c']
3
ghci> foldl (_ -> (+1)) 0 ['a','b','c']

:1:20:
    No instance for (Num Char)
      arising from the literal `0'
    Possible fix: add an instance declaration for (Num Char)
    In the second argument of `foldl', namely `0'
    In the expression: foldl ( _ -> (+ 1)) 0 ['a', 'b', 'c']
    In an equation for `it':
        it = foldl ( _ -> (+ 1)) 0 ['a', 'b', 'c']
ghci>

不同之处在于两件事情:

  • 你放弃了对累加函数的一个输入,并将一个常量函数应用于另一个函数。
  • 这两者之间的积累函数的参数顺序是不同的。
  • 用左边的折叠,累加器就是你丢弃的参数,所以每次你将(+1)到列表中的下一个项目,并最终返回最后一个元素加上一个。

    使用正确的折叠,累加器就是您保留的参数,所以每次您将(+1)应用于之前的结果(从0开始并递增3次(对于列表中的每个项目))。

    如果您使用更明显不同的输入值,可能会更容易看到这里发生了什么:

    Prelude> foldl (_ -> (+1)) 100 [5,6,7]
    8
    Prelude> foldr (_ -> (+1)) 100 [5,6,7]
    103
    

    再次,“最后一个参数加一”和“列表长度加初始值”。

    链接地址: http://www.djcxy.com/p/80725.html

    上一篇: foldl / foldr query

    下一篇: foldl versus foldr behavior with infinite lists