我是否根据foldr使用声音等式推理来定义滤波器?

时间:2010-02-02 16:10:55

标签: haskell filter fold equational-reasoning

嗯,这是使用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中的

step4并不奇怪,因此我们返回ys,即[]

所以现在我们得到了这个:

step 1 (step 2 (step 3 []))

现在,在最内层stepx = 33是奇数,所以我们返回x:ys,即3 : [],这是{ {1}},现在我们得到:

[3]

现在,在内部step 1 (step 2 [3]) stepx = 2并不奇怪,所以我们返回2,即ys,所以现在我们将得到:

[3]

现在,step 1 [3] x = 1是奇数,所以我们返回1x : ys,即1 : [3]

结束: - )。

我的所有动作是对的吗? 非常感谢: - )。

P.S。 [1,3]的定义来自第4章的Real World Haskell一书。

3 个答案:

答案 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)

乍一看,您在特定示例中采取的步骤看起来是正确的。不过,我想指出filterfoldr都可以有效地应用于无限列表 - 这应该表明您的步骤顺序不正确就Haskell而言。