OCaml中的fold_tree
你可能知道,OCaml中有一些高阶函数,例如fold_left、fold_right、filter等。
在我的函数式编程课程中引入了名为fold_tree的函数,它类似于fold_left/right,不是在列表上,而是在(二元)树。它看起来像这样:
let rec fold_tree f a t =
match t with
Leaf -> a |
Node (l, x, r) -> f x (fold_tree f a l) (fold_tree f a r);;
其中树定义为:
type 'a tree =
Node of 'a tree * 'a * 'a tree |
Leaf;;
好的,这是我的问题:fold_tree 函数如何工作?你能给我一些例子并用人类语言解释一下吗?
As You may know, there are higher order functions in OCaml, such as fold_left, fold_right, filter etc.
On my course in functional programming had been introduced function named fold_tree, which is something like fold_left/right, not on lists, but on (binary) trees. It looks like this:
let rec fold_tree f a t =
match t with
Leaf -> a |
Node (l, x, r) -> f x (fold_tree f a l) (fold_tree f a r);;
Where tree is defined as:
type 'a tree =
Node of 'a tree * 'a * 'a tree |
Leaf;;
OK, here's my question: how does the fold_tree function work? Could you give me some examples and explain in human language?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是一个样式建议,将条形放在行的开头。它使案件从哪里开始变得更清楚。为了保持一致性,第一个栏是可选的,但建议使用。
至于它是如何工作的,请考虑以下树:
类型为
int tree
。从视觉上看,
t
看起来像这样:调用fold_tree,我们需要一个函数来组合这些值。根据
Node
情况中的用法,f
采用 3 个参数,所有参数都与树的类型相同,并且返回相同的值。我们将这样做:这将有助于了解每种情况下发生的情况。对于任何
Leaf
,都会返回 a。对于任何Node
,它都会结合存储的值和左右子树折叠的结果。在本例中,我们只是将每片叶子算作 1 的数字相加。该树折叠的结果是10
。Here's a style suggestion, put the bars on the beginning of the line. It makes it clearer where a case begins. For consistency, the first bar is optional but recommended.
As for how it works, consider the following tree:
With the type
int tree
.Visually,
t
looks like this:And calling fold_tree, we'd need a function to combine the values. Based on the usage in the
Node
case,f
takes 3 arguments, all the same type of the tree's and returns the same. We'll do this:It would help to understand what happens in each case. For any
Leaf
, a is returned. For anyNode
, it combines the stored value and the result of folding the left and right subtrees. In this case, we're just adding the numbers where each leaf counts as one. The result on the folding of this tree is10
.让我们举一个例子树。
fold 操作的一般定义是用函数替换构造函数,树上到处都是。
node
是一个函数,它从左侧 something、一个元素和右侧 something 构造一个 something,就像Node
是一个构造函数,它从左子树、节点内容和右子树构造一棵树。leaf
是一个常量,与Leaf
常量构造函数匹配。请注意,函数的类型与类型定义的类型匹配,但类型定义描述
'a 树
的构建,而 Fold 函数描述任何'b< 的构建/代码>。
看起来很像一般折叠的操作仍然称为折叠。例如,在列表上,
List.fold_right
是根据上面定义的一般折叠;List.fold_left
是一种以相反方式应用该函数的变体(fold_left
相当于反向 +fold_right
+反向,尽管它更清晰更有效率)。您自己的
fold_tree
是此常规折叠的简单变体,其中节点函数以与构造函数不同的顺序获取参数:Let's take an example tree.
The general definition of a fold operation is that you replace constructors by functions, everywhere in the tree.
node
is a function that constructs a something from a left something, an element and a right something, just likeNode
is a constructor that constructs a tree from a left subtree, a node content and a right subtree.leaf
is a constant, matching theLeaf
constant constructor.Notice that the types of the functions match those of the type definition, except that where the type definition describes the building of an
'a tree
, the fold function describes the building of any'b
.Operations that look a lot like the general fold are still called fold. For example, on lists,
List.fold_right
is the general fold according to the definition above;List.fold_left
is a variation that applies the function the other way round (fold_left
is equivalent to reverse +fold_right
+ reverse, though it's clearer and more efficient).Your own
fold_tree
is a simple variation of this general fold where the node function takes its arguments in a different order from the constructor:以下是考虑列表上的
fold_right
的方法:例如,使用一个新的二元操作代替 ::(以及一个新的常量代替 [])来重新解释该列表。 。
如果您不想对列表执行任何操作,则可以将函数
cons
作为函数传递,将空列表作为中性元素传递。所以从某种意义上说,fold_right
非常通用:它甚至可以让你根本不丢失任何信息。您问题中的
fold_tree
与树的数据类型的想法相同。如果你想重新解释你的树,你可以向它传递一个新的节点函数,而不是构造函数Node
。如果您想获得一棵相同的树,可以将Leaf
作为中性,将(fun xlr -> Node (l, x, r))
作为函数来应用。与列表的
fold_left
类似,这个示例应用程序并不是很有趣,但这意味着fold_left
是一个非常通用的转换(技术术语是 态射)。例如,您还可以使用函数
(fun xlr -> x + l + r)
对树的元素求和。Here is a way to think about
fold_right
on lists: a list is for instanceand you re-interpret the list with a new binary operation in place of :: (and a new constant instead of []).
If you wanted to do absolutely nothing to your list, you could pass the function
cons
as the function and the empty list as the neutral element. So in a sense,fold_right
is very general: it even allows you not to lose any information at all.The
fold_tree
in your question is the same idea for the datatype of trees. If you want to re-interpret your tree, you pass it a new function for nodes that will be applied instead of the constructorNode
. If you wanted to get an identical tree, you could apply it withLeaf
as neutral and(fun x l r -> Node (l, x, r))
as function.Similarly to
fold_left
for lists, this example application is not very interesting, but it means thatfold_left
is a very general transformation (the technical term is morphism).You can also sum the elements of the tree with the function
(fun x l r -> x + l + r)
, for instance.您可能会喜欢阅读
http://lorgonblog.wordpress.com/2008/ 04/06/catamorphisms-part-two/
http: //lorgonblog.wordpress.com/2008/04/09/catamorphisms-part-third/
位于 F# 中,但 F# 与 OCaml 非常相似。
You might enjoy reading
http://lorgonblog.wordpress.com/2008/04/06/catamorphisms-part-two/
http://lorgonblog.wordpress.com/2008/04/09/catamorphisms-part-three/
which are in F#, but F# is very similar to OCaml.
看起来
f
是一个三参数约简函数,a
是我们约简的中性元素,t
是根,所以:像这样的二进制文件(我不太记得变量类型的语法,所以请在这里居高临下)
如果你想对所有节点求和,函数将被调用如下:
我们会得到
t 作为一个节点匹配,所以我们有:
如果我们再扩展一点,我们得到:
并且我们再次匹配叶子:
最终得到:
希望它有帮助。
It seems that
f
is a three parameter reduction function,a
is the neutral element of our reduction, andt
is the root, so:given a binary like (I don't remember very well the syntax of variant types, so please be condescendent here)
if you want to sum all the nodes, the function will be called like:
and we'll get
t
matched as a node, so we have:if we expand it a little bit more, we get:
and once more, we are matching the leaves:
to finally get:
Hope it helps.