到目前为止,我正试图通过使用fold函数来获取树的产品。我对如何在横向树上使用折叠方法感到困惑
datatype 'a bin_tree = Leaf of 'a
| Node of 'a bin_tree * 'a bin_tree
fun treefold g z Empty = z
| treefold g z (Node (l, x, r)) = g(x, g(treefold g z l, treefold g z r)
答案 0 :(得分:2)
首先,一些关于你尝试的内容不完整的指示。
treefold
函数的基本大小写与值构造函数Empty
匹配,但您没有定义bin_tree
数据类型以包含Empty
值构造函数。< / LI>
Node
值构造函数来成对,但在递归的情况下,你将Node
与三元组匹配。考虑到Simon Shine在二叉树上解释折叠的优秀答案,我们可以推断出这个原因:你的treefold
函数需要一个规范的二叉树(每个节点都有一个值和两个分支)但数据结构你已定义不实现此结构。我不确定你所定义的数据结构是什么,尽管给了它一个好的谷歌(虽然我认为我之前已经实现了它!)。g
应用于z
两次,一次向左分支,一次向右分支。这意味着传递到该位置的值将被包含在每个分支的折叠中两次。我不认为这就是你的意图。(1)和(2)都应该由类型检查器捕获。您应该尝试这个,如果您还没有,并确保您了解类型检查器提供的反馈。这是一个非常有价值的工具。
(3)与您打算编写的函数的性质有关,如果您不理解它,它只会出现故障。
这是定义您定义的数据结构的折叠的一种方法。
structure Tree =
struct
datatype 'a tree = Leaf of 'a
| Node of 'a tree * 'a tree
fun foldl f x t =
case t
of Leaf y => f (x, y) (* The base case *)
| Node (treeL, treeR) =>
let
val l = foldl f x treeL (* Recurse down the left branch *)
in
foldl f l treeR (* Recurse down the right branch *)
end
end
请注意,将foldl
放在Tree
模块中,我们现在如何使用一个函数来反映foldl
结构中的List
函数(以及其他地方) :
- List.foldl;
val it = fn : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
- Tree.foldl;
val it = fn : ('a * 'b -> 'a) -> 'a -> 'b bin_tree -> 'a
这样可以更容易地对列表或树进行参数化。
它的工作原理如下:
- foldl op+ 0 (Node (Leaf 3, Node (Node (Leaf 1, Leaf 2), Leaf 5)));
val it = 11 : int
答案 1 :(得分:2)
折叠二叉树时,
datatype 'a tree = Leaf | Branch of 'a tree * 'a * 'a tree
你可以在different ways中遍历它。你有共同的策略,
(* Pre-order *)
fun treefold_preorder f acc1 Leaf = acc1
| treefold_preorder f acc1 (Branch (left, a, right)) =
let val acc2 = treefold_preorder f acc1 left
val acc3 = f (a, acc2)
val acc4 = treefold_preorder f acc3 right
in acc4 end
(* In-order *)
and treefold_inorder f acc1 Leaf = acc1
| treefold_inorder f acc1 (Branch (left, a, right)) =
let val acc2 = f (a, acc1)
val acc3 = treefold_inorder f acc2 left
val acc4 = treefold_inorder f acc3 right
in acc4 end
(* Post-order *)
and treefold_postorder f acc1 Leaf = acc1
| treefold_postorder f acc1 (Branch (left, a, right)) =
let val acc2 = treefold_postorder f acc1 left
val acc3 = treefold_postorder f acc2 right
val acc4 = f (a, acc3)
in acc4 end
维基百科很好地说明了,
val treelist = treefold op:: []
val treeproduct = treefold op* 1
val treecount = treefold (fn (_, count) => count + 1) 0
如果每个分支/节点都没有&#39; 值,则有序遍历并不重要。
另请参阅如何应用tail-recursion on trees以避免堆栈溢出。
对于涉及树遍历的一些问题,提供遍历的上下文可能很有用paramorphisms:
fun treecata_preorder f acc1 Leaf = acc1
| treecata_preorder f acc1 (branch as Branch (left, a, right)) =
let val acc2 = treecata_preorder f acc1 left
val acc3 = f (a, branch, acc2)
val acc4 = treecata_preorder f acc3 right
in acc4 end
这是treefold_preorder
的略微概括,其中f
被提供给整个branch
。
这可以让你举例如在祖先树中查找谓词为其子树保留的人,
fun treefilter pred =
treecata_preorder (fn (x, xtree, acc) => if pred xtree then x::acc else acc) []
fun branchValue Leaf = NONE
| branchValue (Branch (_, value, _)) = SOME value
fun parents Leaf = []
| parents (Branch (left, _, right)) =
List.mapPartial (fn xopt => xopt) [branchValue left, branchValue right]
type name = string
type age = int
datatype person = Person of name * age
fun retired (Person (_, age)) = age >= 70
fun hasRetiredParent tree = List.exists retired (parents tree)
val personsWithRetiredParents = treefilter hasRetiredParent
树遍历的另一个巧妙概念是zippers(LYAH章节)。