Haskell 在foldr和foldl'中实施或使用;在数据列表中
以下是Prelude中Haskell 在foldr和foldl'中实施或使用;在数据列表中,haskell,Haskell,以下是Prelude中或函数的声明 or = foldr (||) False 如果列表字段至少包含一个True 如果列表包含所有False,则可能发生溢出,我们必须减少到最后一个元素 下面是使用foldl的实现 or = foldl' (||) False 尽管在这里它效率很低,因为它必须减少到列表的最后一个元素,而不管list参数的内容如何。但我们保证不会遇到溢流 所以问题是为什么不使用更安全的foldl'版本 如果列表包含所有False,那么[…]我们必须减少到最后一个元素 这是正确的
或函数的声明
or = foldr (||) False
如果列表字段至少包含一个True
如果列表包含所有False
,则可能发生溢出,我们必须减少到最后一个元素
下面是使用foldl的实现
or = foldl' (||) False
尽管在这里它效率很低,因为它必须减少到列表的最后一个元素,而不管list参数的内容如何。但我们保证不会遇到溢流
所以问题是为什么不使用更安全的foldl'
版本
如果列表包含所有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
是非常好的
如果列表包含所有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
非常好。您所说的“溢出可能发生”是什么意思。是否应该或应该遍历整个列表以查看是否有任何内容为真?如果list参数包含allFalse
,则需要遍历整个列表以进行检查。我错了吗?@utdemir说得对,你必须检查它直到最后一个元素,如果所有的previus元素都是False@user634615,是的,否则你永远不会知道最后一个元素是true@user634615:不,关于遍历,您是正确的。但是(| |)
的参数并不严格,比如说(+)
,你可能会遇到问题。因此,堆栈溢出不会发生在或中。您所说的“溢出可能发生”是什么意思。是否应该或应该遍历整个列表以查看是否有任何内容为真?如果list参数包含allFalse
,则需要遍历整个列表以进行检查。我错了吗?@utdemir说得对,你必须检查它直到最后一个元素,如果所有的previus元素都是False@user634615,是的,否则你永远不会知道最后一个元素是true@user634615:不,关于遍历,您是正确的。但是(| |)
的参数并不严格,比如说(+)
,你可能会遇到问题。因此,堆栈溢出不会在或中发生。明白了。我没有注意(| |)foldr strictOr
在常量空间中运行的定义(没有“溢出”)<可以通过模式匹配或简单地\x y->x`seq`y`seq`x | | y
来定义code>strictOr
。也许这里正在进行一些超级特殊的优化,但我认为此属性是由于foldr
本身造成的。@user2407038:IIRC,GHC不使用上述foldr
实现,而是基于构建器的实现。也就是说,foldr strictOr
在GHCi中对大型列表(如replicate(10^9)False
)进行解释时失败。我不确定优化规则(也就是可能的建设者)是否能解决这个问题。明白了。我没有注意(| |)foldr strictOr
在常量空间中运行的定义(没有“溢出”)<可以通过模式匹配或简单地\x y->x`seq`y`seq`x | | y
来定义code>strictOr
。也许这里正在进行一些超级特殊的优化,但我认为此属性是由于foldr
本身造成的。@user2407038:IIRC,GHC不使用上述foldr
实现,而是基于构建器的实现。也就是说,foldr strictOr
在GHCi中对大型列表(如replicate(10^9)False
)进行解释时失败。我不确定优化规则(也称为可能的构建器)是否会消除这种情况。