在Data.List中实现或在foldr和foldl'中实现

时间:2016-03-18 09:47:19

标签: haskell

以下是Prelude

or函数的声明
or = foldr (||) False

如果列表字段至少包含一个True,则此实现很好 如果列表包含所有False,则可能发生溢出,我们必须减少到最后一个元素

以下是使用foldl'

的实现
or = foldl' (||) False

这里虽然效率很低,但它必须减少到列表的最后一个元素,而不管列表参数的内容如何。但我们保证不会遇到溢出。

所以问题是为什么不使用更安全的foldl'版本

1 个答案:

答案 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完全没问题。