为什么foldl与forFn函数没有短路?

时间:2016-06-22 12:36:27

标签: haskell lazy-evaluation fold thunk

我的理解是foldlfoldr执行如下:

foldl f a [1..30] => (f (f (f ... (f a 1) 2) 3) ... 30)

foldr f a [1..30] => (f 1 (f 2 (f 3 (f ....(f 30 a)))))..)

所以.. foldr (&&) False (repeat False)可以短路,因为最外层的f看到(&&) False ((&&) False (....))看到第一个参数为false,不需要评估第二个参数(这是一个大的thunk)。

所以

会发生什么
andFn :: Bool -> Bool -> Bool
andFn _ False = False
andFn x True  = x

foldl andFn True (repeat False)  -- =>

-- (andFn (andFn ...(andFn True False) ... False) False)
--  ^^ outermost andFn

但这需要永远。

我认为outermost andFn会知道通过第二个参数的模式匹配,答案是False ..

这里还发生了什么?

1 个答案:

答案 0 :(得分:17)

foldrfoldl之间的差异大于andFn的参数顺序。

foldr f z (x:xs) = f x (foldr f z xs)
foldl f z (x:xs) = foldl f (f z x) xs

请注意foldr如何立即将控件转移到f:如果f是懒惰的,则可以避免foldr f z xs的计算。

相反,foldl将控制转移到... foldl:只有在达到基本情况时才会开始使用函数f

foldl f z [] = z      -- z contains the chained f's, which NOW get evaluated

因此foldl f z infiniteList 总是分歧,无论f是什么:整个infiniteList需要在任何实际计算发生之前完全迭代。 (非主题:这就是为什么,即使它有效,foldl通常表现糟糕,foldl'在实践中更常用。)

特别是发布的示例

foldl andFn True (repeat False)  -- =>
-- (andFn (andFn ...(andFn True False) ... False) False)
--  ^^ outermost andFn

部分错误。 “最外面的andFn”实际上是 last 一个,即与repeat False中的 last 元素相关的那个。但是没有这样的野兽。