这是我的代码:
boolTrueList :: [Bool] -> Bool
boolTrueList xs
| length (filterFalse xs) > 0 = False
| otherwise = True
where
filterFalse = filter (==False)
这是完美的工作,但是我想用foldr / foldl重写同样的东西,但我被卡住了。
我的想法是折叠列表,直到找到错误值,然后停止。 任何提示?
答案 0 :(得分:12)
我的想法是折叠列表,直到找到错误值,然后停止。任何提示?
如果您想提早停止,则必须使用foldr
。 foldl
总是必须遍历整个列表(所以在无限列表中根本不起作用)。
所以你想要
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
使用高阶函数来避免迭代是不够的,我们应该避免迭代思维。考虑开放式表达而不是“此时,这个值会传播”。通常情况下,迭代只是生成开放式表达式的低级方式,而且由于我们的语言迫使我们这样做,我们的思维方式常常被困在它上面,即使我们的语言允许我们思考表达式水平。