繁体   English   中英

树折操作?

[英]Tree Fold operation?

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

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

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

我总是认为折叠是一种通过其他函数系统地替换构造函数的方法。 因此,例如,如果您有自己动手的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值应转化为b ,另一个替代构造的Cons构造,告诉如何的第一个值Cons构造(类型a )应与类型的值相结合b (为什么b ?因为fold已经递归地应用!)产生一个新的b ,最后是一个List a来应用整个she-bang到 - 结果为b

在你的情况下, tfold的类型应该是(a -> b) -> (b -> b -> b) -> Tree a -> b通过类似的推理; 希望你能从那里拿走它!

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

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

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

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

因此,对于叶子,您应该只取其中的值,对于分支,递归地为两个子节点中的每一个应用折叠, 并将两个结果与提供的函数(树折叠的函数) 组合 编辑:)当从叶子“获取”值时,你可以另外转换它们,应用一元函数。 因此,在一般情况下,你的折叠需要两个用户提供的功能,一个是Lf ,另一种用于组合为r的第r esults ecursively折叠分支节点的树状成分(即分行) Br

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

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

(更新2019-01-26)如果组合操作是关联的,则可以重新括号,如+ :( (a 1 +a 2 )+a 3 == a 1 +(a 2 +a 3 ) 数据类型连同这种关联操作和“零”元素( a+0 == 0+a == a )被称为“Monoid”,折叠“进入”Monoid的概念被Foldable类型捕获类。

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

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) = -- ...

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

折叠是使用操作将数据结构“压缩”为单个值的操作。 根据您是否具有起始值和执行顺序(例如,对于具有foldlfoldrfoldl1foldr1 ),存在各种变化,因此正确的实现取决于您的分配。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM