我的理解是foldl
和foldr
执行如下:
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
..
这里还发生了什么?
答案 0 :(得分:17)
foldr
和foldl
之间的差异大于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 元素相关的那个。但是没有这样的野兽。