嗯,这是使用foldr的过滤函数的定义:
myFilter p xs = foldr step [] xs
where step x ys | p x = x : ys
| otherwise = ys
例如,假设我有这个功能:
myFilter odd [1,2,3,4]
所以它将是:
foldr step [] [1,2,3,4]
这将是
step 1 (foldr step [] [2,3,4])
这将是
step 1 (step 2 (foldr step [] [3,4]))
这将是
step 1 (step 2 (step 3 (foldr step [] [4])))
这将是
step 1 (step 2 (step 3 (step 4 (foldr step [] []))))
和foldr step [] []
是[]
所以:
step 1 (step 2 (step 3 (step 4 [])))
现在我们将实际进入step
功能
以下是step
函数中myFilter
的定义,从上面开始:
step x ys | p x = x : ys
| otherwise = ys
另外,我提醒您p
实际上是我们示例中的odd
函数。
step 1 (step 2 (step 3 (step 4 [])))
和
最内层的x = 4
中的 step
和4
并不奇怪,因此我们返回ys
,即[]
所以现在我们得到了这个:
step 1 (step 2 (step 3 []))
现在,在最内层step
,x = 3
和3
是奇数,所以我们返回x:ys
,即3 : []
,这是{ {1}},现在我们得到:
[3]
现在,在内部step 1 (step 2 [3])
,step
和x = 2
并不奇怪,所以我们返回2
,即ys
,所以现在我们将得到:
[3]
现在,step 1 [3]
和x = 1
是奇数,所以我们返回1
,x : ys
,即1 : [3]
。
结束: - )。
我的所有动作是对的吗? 非常感谢: - )。 P.S。 [1,3]
的定义来自第4章的Real World Haskell一书。
答案 0 :(得分:5)
在第一次阅读时,这对我来说是正确的。
要记住的重要一点是,为了实现懒惰的评估,Haskell实际上会以另一种方式看待事物。换句话说,真正的序列更像是
step 1 (step 2 (step 3 (step 4 [])))
变为
step 1 <block1>
成为
[1, <block1>]
然后如果您尝试从该列表中提取下一个元素,它将评估
[1, step 2 <block2>]
成为
[1, <block2>]
然后尝试评估
[1, step 3 (step 4 [])]
变成
[1, step 3 <block3>]
成为
[1, 3, <block3>]
等。这花了我一点时间来理解。由于foldr
似乎是从“由内而外”进行评估,但foldl
是从“外部”评估foldr
将是懒惰的(它是),这对我来说是违反直觉的。 ,foldl
是严格的。但是如果你按照我上面概述的方式来思考它,那么(对我来说,无论如何)都是有道理的。
答案 1 :(得分:4)
只是扩展惰性评估顺序:基本上Haskell总是首先评估函数,而不是直到它必须查看参数。
如果使用myFilter
的调用结果(例如打印),将按以下顺序评估该函数:
myFilter odd [1,2,3,4]
首先评估myFilter
函数:
foldr step [] [1,2,3,4]
现在foldr
是最外面的函数并进行评估:
step 1 (foldr step [] [2,3,4])
现在step
被评估产生1
,因为1
是奇数:
1 : foldr step [] [2,3,4]
现在结果列表的第一个元素可用,并且可以由调用函数使用。如果调用函数也使用以下元素继续进行评估
使用foldr
:
1 : step 2 (foldr step [] [3,4])
step
的评估现在不会产生任何新元素,因为2是偶数:
1 : foldr step [] [3,4]
再次foldr
:
1 : step 3 (foldr step [] [4])
现在评估step
会产生3
:
1 : 3 : foldr step [] [4]
评估foldr
;
1 : 3 : step 4 (foldr step [] [])
再次step
:
1 : 3 : foldr step [] []
最后foldr
评估为空列表:
1 : 3 : []
答案 2 :(得分:2)
乍一看,您在特定示例中采取的步骤看起来是正确的。不过,我想指出filter
和foldr
都可以有效地应用于无限列表 - 这应该表明您的步骤顺序不正确就Haskell而言。