所以,我真的在煎我的大脑,试着理解foldl.foldr的成分。 这是一个例子:
(foldl.foldr) (+) 1 [[1,2,3],[4,5,6]]
结果是22,但这里到底发生了什么?
对我来说,看起来就是这样:foldl (+) 1 [6,15]
。
我的疑问与foldr
部分有关。它不应该将1添加到所有子列表中吗?像这样:foldr (+) 1 [1,2,3]
。
在我脑海中,1只添加了一次,是不是? (可能不是,但我想知道如何/为什么!)。
我很困惑(也许让所有人感到困惑,哈哈)。 谢谢!
答案 0 :(得分:14)
(foldl.foldr) (+) 1 [[1,2,3],[4,5,6]]
变为
foldl (foldr (+)) 1 [[1,2,3],[4,5,6]]
所以你得到了
foldl (foldr (+)) (foldr (+) 1 [1,2,3]) [[4,5,6]]
在foldl
或的第一步之后
foldl (foldr (+)) 7 [[4,5,6]]
如果我们评估应用的foldr
(除非严格分析器启动,它实际上仍然是未评估的thunk,直到foldl
遍历整个列表,但下一个表达式更具可读性它评估),那就变成了
foldl (foldr (+)) (foldr (+) 7 [4,5,6]) []
最后
foldl (foldr (+)) 22 []
~> 22
答案 1 :(得分:13)
让我们来看看foldl . foldr
。他们的类型是
foldl :: (a -> b -> a) -> (a -> [b] -> a)
foldr :: (c -> d -> d) -> (d -> [c] -> d)
我故意使用了不同的类型变量,并添加了括号,以便我们现在将它们视为一个参数的函数(它们的结果是函数)变得更加明显。查看foldl
我们看到它是一种提升函数:给定一个函数使用a
从a
生成b
,我们将其提升以便它可以在{ {1}}(通过重复计算)。函数[b]
类似,只是反转了参数。
现在如果我们申请foldr
会怎样?首先,让我们派生类型:我们必须统一类型变量,以便foldl . foldr
的结果与foldr
的参数匹配。所以我们必须替换:foldl
:
a = d, b = [c]
所以我们得到
foldl :: (d -> [c] -> d) -> (d -> [[c]] -> d)
foldr :: (c -> d -> d) -> (d -> [c] -> d)
它的含义是什么?首先,foldl . foldr :: (c -> d -> d) -> (d -> [[c]] -> d)
解除类型foldr
的参数以处理列表,并反转其参数以便我们得到c -> d -> d
。接下来,d -> [c] -> d
再次提升此功能以处理foldl
- [[c]]
列表。
在您的情况下,被提升的操作[c]
是关联的,因此我们不关心其应用程序的顺序。双提升只是创建一个函数,对所有嵌套元素应用操作。
如果我们只使用(+)
,效果会更好:我们可以举多次,比如
foldl
答案 2 :(得分:2)
实际上,(foldl.foldr) f z xs === foldr f z (concat $ reverse xs)
。
即使f
是关联操作,正确的应用程序序列也很重要,因为它会对性能产生影响。
我们从
开始(foldl.foldr) f z xs
foldl (foldr f) z xs
用g = foldr f
和[x1,x2,...,xn_1,xn] = xs
写一下,这是
(...((z `g` x1) `g` x2) ... `g` xn)
(`g` xn) ((`g` xn_1) ... ((`g` x1) z) ... )
foldr f z $ concat [xn,xn_1, ..., x1]
foldr f z $ concat $ reverse xs
因此,在您的情况下,正确的缩减序列是
(foldl.foldr) 1 [[1,2,3],[4,5,6]]
4+(5+(6+( 1+(2+(3+ 1)))))
22
即便,
Prelude> (foldl.foldr) (:) [] [[1..3],[4..6],[7..8]]
[7,8,4,5,6,1,2,3]
同样,(foldl.foldl) f z xs == foldl f z $ concat xs
。使用snoc a b = a++[b]
,
Prelude> (foldl.foldl) snoc [] [[1..3],[4..6],[7..8]]
[1,2,3,4,5,6,7,8]
此外,(foldl.foldl.foldl) f z xs == (foldl.foldl) (foldl f) z xs == foldl (foldl f) z $ concat xs == (foldl.foldl) f z $ concat xs == foldl f z $ concat (concat xs)
等:
Prelude> (foldl.foldl.foldl) snoc [] [[[1..3],[4..6]],[[7..8]]]
[1,2,3,4,5,6,7,8]
Prelude> (foldl.foldr.foldl) snoc [] [[[1..3],[4..6]],[[7..8]]]
[7,8,1,2,3,4,5,6]
Prelude> (foldl.foldl.foldr) (:) [] [[[1..3],[4..6]],[[7..8]]]
[7,8,4,5,6,1,2,3]