树折操作?

时间:2012-02-21 03:01:02

标签: haskell tree fold

我正在Haskell中学习一个类,我们需要为以下定义的树定义折叠操作:

data Tree a = Lf a | Br (Tree a) (Tree a)

我似乎无法找到关于“tfold”操作的任何信息,或者它真的应该做什么。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:11)

我总是认为折叠是一种系统地用其他函数替换构造函数的方法。因此,例如,如果您有自己动手List类型(定义为data List a = Nil | Cons a (List a)),则相应的折叠可以写为:

listfold nil cons Nil = nil
listfold nil cons (Cons a b) = cons a (listfold nil cons b)

或者,或许更简洁,如:

listfold nil cons = go where
    go Nil = nil
    go (Cons a b) = cons a (go b)

listfold的类型为b -> (a -> b -> b) -> List a -> b。也就是说,需要两个“替代建设者”;一个告诉如何将Nil值转换为bCons构造函数的另一个替换构造函数,告诉Cons构造函数的第一个值(类型为{ {1}})应该与a类型的值组合(为什么b?因为折叠已经递归应用!)以产生新的b,最后是{ {1}}将整个she-bang应用于 - b

在您的情况下,List a的类型应该是类似推理的b;希望你能从那里拿走它!

答案 1 :(得分:3)

想象一下,您定义了一个树应该以下面的方式显示,

<1 # <<2#3> # <4#5>>>

折叠这样的树意味着用数据类型的成分(这里是节点的两个子节点,这里是递归执行的折叠结果对实际提供的操作替换每个分支节点他们自己,每一个,一个树),例如+,产生

(1 + ((2+3) + (4+5)))

因此,对于叶子,你应该只取它们内部的值,对于分支,递归地为两个子节点中的每一个应用折叠,并且将两个结果与所提供的函数组合,树被折叠的那个。 (编辑:)当从“叶子”中“获取”值时,您可以另外转换它们,应用一元函数。所以一般来说,折叠需要两个用户提供的函数,一个用于 leaves Lf,另一个用于组合 r r 的结果以递归方式折叠分支节点Br的树状成分(即分支)。

您的树数据类型可能已被不同地定义,例如可能是空叶子,内部节点也带有值。然后,您必须提供要使用的默认值而不是空叶节点,以及三向组合操作。您仍然可以使用两个函数定义的折叠,这些函数对应于数据类型定义的两种情况

这里要实现的另一个区别是,你折叠了什么,以及你如何折叠。即您可以使用线性方式折叠树,(1+(2+(3+(4+5)))) == ((1+) . (2+) . (3+) . (4+) . (5+)) 0,或者可以以树状方式折叠线性列表((1+2)+((3+4)+5)) == (((1+2)+(3+4))+5)。这完全取决于你如何将结果“表达式”括起来。当然,在经典的折叠中,表达式的结构遵循折叠的数据结构;但是variations do exist。另请注意,组合操作可能不严格,并且它消耗/生成的“ r esult”类型可能表达 compound (列表等),以及原子(数字等),价值观。

(更新2019-01-26)如果组合操作是关联的,则可以重新加括号,例如+(a1+a2)+a3 == a1+(a2+a3)。与这种关联操作和“零”元素(a+0 == 0+a == a)一起的数据类型被称为“Monoid”,并且Foldable类型类捕获折叠成“Monoid”的概念。

答案 2 :(得分:1)

列表中的折叠是从列表减少到单个元素。它接受一个函数,然后将该函数一次两个地应用于元素,直到它只有一个元素。例如:

Prelude> foldl1 (+) [3,5,6,7]
21

...是通过逐个操作找到的:

3 + 5 == 8
8 + 6 == 14
14 + 7 == 21

可以写一个折叠

ourFold :: (a -> a -> a) -> [a] -> a
ourFold _         [a]        = a -- pattern-match for a single-element list. Our work is done.
ourFold aFunction (x0:x1:xs) = ourFold aFunction ((aFunction x0 x1):xs)

树折会执行此操作,但会向上或向下移动树的分支。要做到这一点,首先需要进行模式匹配,看看你是在Leaf还是Branch上运行。

treeFold _ (Lf a)   = Lf a -- You can't do much to a one-leaf tree
treeFold f (Br a b) = -- ...

剩下的由你来完成,因为它是家庭作业。如果你遇到困难,首先要考虑应该是什么类型。

答案 3 :(得分:1)

折叠是使用操作将数据结构“压缩”为单个值的操作。根据您是否具有起始值和执行顺序(例如,对于您有foldlfoldrfoldl1foldr1的列表,有一些变体,因此正确的实施取决于你的任务。

我猜你的tfold应该简单地用它的值替换所有叶子,并且用给定操作的应用程序替换所有分支。绘制一个带有一些数字的示例树,给出像(+)这样的操作“崩溃”他。在此之后,编写一个相同的函数应该很容易。