文件夹如何在此数据树上工作?

时间:2019-05-28 03:37:50

标签: haskell functional-programming

我知道文件夹在Leaf上如何工作,但我不知道文件夹在Node上如何工作。如果我们已经有f和z作为参数,则参数\ x z'是什么。假设我们有

tree = Node [Leaf 1, Leaf 2, Node [Leaf 1, Leaf 3]]

此代码的工作方式

foldr (+) 0 tree
data RoseTree a =  Leaf a | Node [RoseTree a] 
instance Foldable RoseTree where 
    foldr f z (Leaf x) = f x z
    foldr f z (Node ns) = 
        foldr (\x z' -> foldr f z' x) z ns 

2 个答案:

答案 0 :(得分:6)

foldr的{​​{1}}定义调用Node列表中的foldr。然后,在该RoseTree内部,使用当前累加器作为初始参数,在每个子树上调用foldr

基本上,即使函数两次调用foldr,它每次都针对不同的类型调用它,因此只有一个是递归的。另一个是为foldr定义的foldr

答案 1 :(得分:4)

我们可以使用您给定的示例数据讨论实现方式:

foldr (+) 0 (Node [Leaf 1, Leaf 2, Node [Leaf 1, Leaf 3]])

因此我们这里有一个Node,因此我们采用第二个子句,因此将其替换为:

foldr (\x z' -> foldr (+) z' x) 0 [Leaf 1, Leaf 2, Node [Leaf 1, Leaf 3]]

外部foldr因此在列表上起作用,这意味着documentation

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

因此,意味着上述foldr被替换为:

foldr (+) (foldr (+) (foldr (+) 0 (Node [Leaf 1, Leaf 3])) (Leaf 2)) (Leaf 1)

因此外部函数现在为foldr (+) (...) (Leaf 1),这是我们foldr定义的第一子句,因此等于:

(+) 1 (foldr (+) (foldr (+) 0 (Node [Leaf 1, Leaf 3])) (Leaf 2))

然后我们可以撤消foldr (+) (...) (Leaf 2)表达式,该表达式的处理方式相同:

(+) 1 ((+) 2 (foldr (+) 0 (Node [Leaf 1, Leaf 3])))

或更简单:

1 + 2 + foldr (+) 0 (Node [Leaf 1, Leaf 3])

最后,我们再次有一个foldr (+) 0可以在Node上运行,因此再次产生了如上所述的评估结果:

1 + 2 + foldr (+) (foldr (+) 0 (Leaf 3)) (Leaf 1)

因此,我们可以再次将外部foldr (+)评估为:

1 + 2 + (+) 1 (foldr (+) 0 (Leaf 3))

和内部foldr (+)用于:

1 + 2 + (+) 1 ((+) 3 0)

或更简单:

1 + 2 + 1 + 3 + 0

等效于:

7

Leaf中节点的总和。

请务必注意,外部 foldr (此处用斜体表示)与内部foldr的功能不同实现中的 foldr (此处用粗体表示):外部的一个用作函子,而内部的一个是我们在列表中定义的函子。 instance Foldable RoseTree

instance Foldable RoseTree where 
    foldr f z (Leaf x) = f x z
    foldr f z (Node ns) = foldr (\x z' -> foldr f z' x) z ns

如果我们因此在foldr上使用函数Tree和初始值f执行z,则将所有叶子替换为f x z ,(对于foldr (+) 0就是(+) x 0x + 0而言)。

Node将导致 folding 值一起折叠,其中将拖尾元素的折叠结果用作与head元素的折叠的初始值。