折叠.foldr函数组合 - Haskell

deh*_*ehq 8 haskell fold function-composition

所以,我真的在煎我的大脑,试着理解foldl.foldr的成分.这是一个例子:

(foldl.foldr) (+) 1 [[1,2,3],[4,5,6]]
Run Code Online (Sandbox Code Playgroud)

结果是22,但这里到底发生了什么?

对我来说,这就是发生的事情:foldl (+) 1 [6,15].我的疑问与该foldr部分有关.它不应该将1添加到所有子列表中吗?像这样:foldr (+) 1 [1,2,3].在我脑海中,1只添加了一次,是不是?(可能不是,但我想知道如何/为什么!).

我很困惑(也许让所有的困惑,哈哈).谢谢!

Dan*_*her 14

(foldl.foldr) (+) 1 [[1,2,3],[4,5,6]]
Run Code Online (Sandbox Code Playgroud)

foldl (foldr (+)) 1 [[1,2,3],[4,5,6]]
Run Code Online (Sandbox Code Playgroud)

所以你得到了

foldl (foldr (+)) (foldr (+) 1 [1,2,3]) [[4,5,6]]
Run Code Online (Sandbox Code Playgroud)

在第一步之后foldl,或

foldl (foldr (+)) 7 [[4,5,6]]
Run Code Online (Sandbox Code Playgroud)

如果我们评估应用foldr(除非严格性分析器启动,它实际上仍然是一个未评估的thunk,直到foldl遍历整个列表,但下一个表达式更具可读性,并评估)

foldl (foldr (+)) (foldr (+) 7 [4,5,6]) []
Run Code Online (Sandbox Code Playgroud)

最后

foldl (foldr (+)) 22 []
~> 22
Run Code Online (Sandbox Code Playgroud)


Pet*_*lák 13

我们来看看foldl . foldr.他们的类型是

foldl :: (a -> b -> a) -> (a -> [b] -> a)
foldr :: (c -> d -> d) -> (d -> [c] -> d)
Run Code Online (Sandbox Code Playgroud)

我有意使用不同类型变量和I加入括号以致变得更加明显,我们现在视其为一个参数的函数(并且它们的结果的函数).纵观foldl我们看到它是一种升降功能的:鉴于生产函数aa使用b,我们抬起它,使其工作在[b](重复计算).功能foldr类似,只是反转的参数.

如果我们申请会发生什么foldl . foldr?首先,让我们派生出类型:我们必须统一类型变量,以便foldr匹配参数的结果foldl.所以我们必须替换a = d, b = [c]:

foldl :: (d -> [c] -> d) -> (d -> [[c]] -> d)
foldr :: (c -> d   -> d) -> (d -> [c] -> d)
Run Code Online (Sandbox Code Playgroud)

所以我们得到了

foldl . foldr :: (c -> d -> d) -> (d -> [[c]] -> d)
Run Code Online (Sandbox Code Playgroud)

它的含义是什么?首先,foldr提升类型的参数c -> d -> d以在列表上工作,并反转其参数以便我们得到d -> [c] -> d.接下来,foldl再次提升此功能以进行处理[[c]]- 列表[c].

在您的情况下,提升的操作(+)是关联的,因此我们不关心其应​​用程序的顺序.双提升只是创建一个在所有嵌套元素上应用操作的函数.

如果我们只使用foldl,效果更好:我们可以提升多次,比如

foldl . foldl . foldl . foldl
    :: (a -> b -> a) -> (a -> [[[[b]]]] -> a)
Run Code Online (Sandbox Code Playgroud)