如果列表只有True值,则使用foldl返回True,否则返回false

时间:2012-12-06 13:35:39

标签: haskell

这是我的代码:

boolTrueList :: [Bool] -> Bool
boolTrueList xs
  | length (filterFalse xs) > 0 = False
  | otherwise = True
  where
    filterFalse = filter (==False)

这是完美的工作,但是我想用foldr / foldl重写同样的东西,但我被卡住了。

我的想法是折叠列表,直到找到错误值,然后停止。 任何提示?

2 个答案:

答案 0 :(得分:12)

  

我的想法是折叠列表,直到找到错误值,然后停止。任何提示?

如果您想提早停止,则必须使用foldrfoldl总是必须遍历整个列表(所以在无限列表中根本不起作用)。

所以你想要

foldr combine default list

default是空列表的结果,此处为True。现在,我们将如何结合?

遇到False时,我们想立即返回False,所以

combine False _ = False

当值为True时,我们必须继续,所以

combine True more = more

换句话说,combine = (&&),所以

boolTrueList = foldr (&&) True

或者更短的

boolTrueList = and

答案 1 :(得分:5)

有一种方法可以考虑我发现非常有用和直观的折叠(我可能在某处读过)。请注意,这可能无法提供最有效的解决方案,但我的关注点是明确的。

不要将fold视为从列表构建值的函数,而是将其视为在列表元素之间插入运算符的方法。当你这样做时,折叠然后成为一种将列表转换为表达式的方法。例如,以下内容:

foldr op I [A,..,Z]

将产生以下扩展:

A op .. op Z op I 

如果你将这种想法应用于你的问题,那么你需要做的就是问自己,如果A .. Z是真的,那么我和我应该做什么才能确保你得到真的?作为提示,我通常是与op相关的标识元素(一个不会改变表达式的值,就像0将用于添加)。

嗯,我们从逻辑上知道,并且(&&)只有在其所有操作数都为真时才为真。同样,True是关于&&的标识元素。所以说,你的扩展将是:

A && .. && Z && True

所以你的弃牌是:

foldr (&&) True [A,..,Z]

这意味着你的职能是:

boolTrueList x = foldr (&&) True x

或者采用更无瑕疵的风格:

boolTrueList = foldr (&&) True

使用高阶函数来避免迭代是不够的,我们应该避免迭代思维。考虑开放式表达而不是“此时,这个值会传播”。通常情况下,迭代只是生成开放式表达式的低级方式,而且由于我们的语言迫使我们这样做,我们的思维方式常常被困在它上面,即使我们的语言允许我们思考表达式水平。