以下是Prelude
中or
函数的声明
or = foldr (||) False
如果列表字段至少包含一个True
,则此实现很好
如果列表包含所有False
,则可能发生溢出,我们必须减少到最后一个元素
以下是使用foldl'
的实现or = foldl' (||) False
这里虽然效率很低,但它必须减少到列表的最后一个元素,而不管列表参数的内容如何。但我们保证不会遇到溢出。
所以问题是为什么不使用更安全的foldl'
版本
答案 0 :(得分:4)
如果列表包含所有
False
,那么[...]我们必须减少到最后一个元素。
这是正确的。
如果列表包含所有
False
,则可能发生溢出[...]。
那不是。除(+)
之类的功能外,两个参数中的(||)
都不严格。它只与左边的模式匹配:
(||) :: Bool -> Bool -> Bool
(||) True _ = True
(||) _ x = x
因此,如果我们对列表使用foldr
的定义,我们会得到:
foldr (||) False [False,False])
= False || (foldr (||) False [False]) -- use: False || x = x
= foldr (||) False [False]
= False || (foldr (||) False []) -- use: False || x = x
= foldr (||) False []
= False
但是,如果我们使用一个函数,其中两个参数需要完全评估,我们会遇到问题:
foldr (+) 0 [1,2]
= 0 + (foldr (+) 1 [2]) -- cannot reduce (+), since it needs right hand side
= 0 + (1 + (foldr (+) 2 []))
= 0 + (1 + (2))
= 0 + (3)
= 3
在这种情况下,您应该使用foldl'
。但对于(||)
或(:)
这样的右延函数,foldr
完全没问题。