这是我的代码:
boolTrueList :: [Bool] -> Bool
boolTrueList xs
| length (filterFalse xs) > 0 = False
| otherwise = True
where
filterFalse = filter (==False)
Run Code Online (Sandbox Code Playgroud)
这是完美的工作,但我想用foldr/foldl重写相同的东西,但我被卡住了.
我的想法是折叠一个列表,直到我找到一个假值,然后停止.任何提示?
Dan*_*her 12
我的想法是折叠一个列表,直到我找到一个假值,然后停止.任何提示?
如果你想提早停止,你必须使用foldr.foldl总是必须遍历整个列表(因此在无限列表中根本不起作用).
所以你要
foldr combine default list
Run Code Online (Sandbox Code Playgroud)
这default是一个空列表的结果,就在True这里.现在,我们将如何结合?
当False遇到a 时,我们想立即返回False,所以
combine False _ = False
Run Code Online (Sandbox Code Playgroud)
当价值是True,我们必须继续,所以
combine True more = more
Run Code Online (Sandbox Code Playgroud)
换句话说combine = (&&),如此
boolTrueList = foldr (&&) True
Run Code Online (Sandbox Code Playgroud)
或者,甚至更短
boolTrueList = and
Run Code Online (Sandbox Code Playgroud)
有一种方法可以考虑我发现非常有用和直观的折叠(我可能在某处读过).请注意,这可能无法提供最有效的解决方案,但我在此明确表示关注.
不要将fold视为从列表构建值的函数,而是将其视为在列表元素之间插入运算符的方法.当你这样做时,折叠然后成为一种将列表转换为表达式的方法.例如,以下内容:
foldr op I [A,..,Z]
Run Code Online (Sandbox Code Playgroud)
将产生以下扩展:
A op .. op Z op I
Run Code Online (Sandbox Code Playgroud)
如果你将这种想法应用到你的问题中,那么你需要做的就是问自己,如果A .. Z是真的,那么我和我应该如何才能得到真的?作为提示,我通常是关于op的标识元素(不改变表达式的值,如0将用于添加).
好吧,我们从逻辑上知道,如果所有操作数都为真,则(&&)只是真的.同样,True是关于&&的标识元素.所以说,你的扩展将是:
A && .. && Z && True
Run Code Online (Sandbox Code Playgroud)
所以你的弃牌是:
foldr (&&) True [A,..,Z]
Run Code Online (Sandbox Code Playgroud)
这意味着你的功能是:
boolTrueList x = foldr (&&) True x
Run Code Online (Sandbox Code Playgroud)
或者更自由的风格:
boolTrueList = foldr (&&) True
Run Code Online (Sandbox Code Playgroud)
使用高阶函数来避免迭代是不够的,我们应该避免迭代思维.考虑开放式表达式而不是"此时此值将传播".通常情况下,迭代只是生成开放式表达式的低级方式,而且由于我们的语言迫使我们这样做,我们的思维方式经常被困在其中,即使我们的语言允许我们思考表达式水平.