我正在尝试filter
使用foldr
。我有一个解决方案,但不知道为什么我的版本不起作用。
foldr
像这样工作:
>>>foldr op z (xs:x)
x op z
Run Code Online (Sandbox Code Playgroud)
然后重复,对吗?当x是列表中的最后一个元素时。
我现在有
myFilter pred = foldr op z
where
z = []
op x xs = if pred x then x
Run Code Online (Sandbox Code Playgroud)
这不起作用,给出parse error (possibly incorrect indentation or mismatched brackets)
错误。
操作只是给x
到pred
,如果是true
,退货x
,否则跳过它。foldr
起作用的方式是,它不断在xs
传递的列表上循环。那我为什么要做
op x xs = if pred x then x : xs else xs
Run Code Online (Sandbox Code Playgroud)
并告诉它继续进行,xs
即使foldr
已经进行了?
foldr :: (a -> b -> b) -> b -> [a] -> b
在a
s 的输入列表上循环并操纵a b
(表示循环的状态)。op
的工作是a
从输入列表中获取当前状态b
,然后计算一个新状态。foldr
确保op
为列表中的每个项目调用该方法。
在您的情况下filter
,b
碰巧也是的列表a
。因此,您的代码正在讨论a
s的两个不同列表-输入列表和输出列表。您op
必须决定是否将其放入x
输出列表中?
为了明确起见,这是您的代码,其中的变量命名更具暗示性。
filter :: (a -> Bool) -> [a] -> [a]
filter pred = foldr addToOutputIfNecessary initialOutput
where
initialOutput = []
addToOuputIfNecessary itemFromInput currentOutput =
if pred itemFromInput
then itemFromInput:currentOutput
else currentOutput
Run Code Online (Sandbox Code Playgroud)
因此,当我们currentOutput
从返回时addToOutputIfNecessary
,并不是foldr
要继续。(foldr
将始终单独继续下一个输入元素-您无需告诉它继续。)只是说循环的状态并未更改此迭代;我们决定不向输出列表添加项目。
希望这可以帮助!如果您不了解任何内容,请在评论中让我知道。
foldr
封装将列表中的元素组合在一起以及折叠列表的其余部分的结果所涉及的递归。xs
不是您输入内容的尾巴;这是折叠输入尾部的结果。
您可以通过专注于您想做op
的事情,并通过重构来不强调它的作用,从而对此加以强调
op x xs = if pred x then x : xs else xs
Run Code Online (Sandbox Code Playgroud)
至
-- (x:) xs == x:xs
-- id xs == xs
op x xs = (if pred x then (x:) else id) xs
Run Code Online (Sandbox Code Playgroud)
可以减少到
op x = if pred x then (x:) else id
Run Code Online (Sandbox Code Playgroud)
换句话说,给定列表的第一个元素,您将如何处理它:将x
其添加到递归结果之前,还是按原样返回该结果?
归档时间: |
|
查看次数: |
88 次 |
最近记录: |