我想用一个基本值z,一个组合函数g来减少一个二叉树。该函数必须具有O(n)的作用力,但跨度为O(log n)。
树定义为datatype tree = Leaf of int | Node of tree * tree
。
这是我的代码
treeReduce : ('a * 'a -> 'a) -> 'a -> 'a tree -> 'a
Requires: g is associative, z is an identity of g
Ensures: treereduce g z T ~= foldr g z (inord T) ~= foldl g z (inord T)
fun treeReduce (g: 'a * 'a -> 'a) (z : 'a) (Empty: 'a tree)=z
| treeReduce g z (Node(l,x,r))=g(g(treeReduce g z l,x),treeReduce g z r)
但是,这不能产生正确的答案。我在做什么错了?
答案 0 :(得分:0)
您说您的代码不能产生正确的答案,但是您没有说您得到什么答案以及为什么这是不正确的。因此,也许您的代码中存在一个错误,或者您以另一种想要的顺序遍历树。如果要找出答案,我会稍微重新格式化您的代码:
fun treeReduce g z0 Empty = z0
| treeReduce g z0 (Node (left, x, right)) =
let val z1a = treeReduce g z0 left
val z1b = treeReduce g z0 right
val y = g (z1a, x)
val z = g (z1b, y)
in z end
我使用了 let-in-end 来更准确地为每个计算命名。
让我感到奇怪的是,z1a
和z1b
都基于z0
。将其与preorder, inorder and postorder traversal of trees in SML的实现进行比较,您会发现您可能希望累计值沿着每个节点传播。对于您来说,z1a
不会被带到right
分支。
令我惊讶的另一件事是treeReduce
的类型签名:
('a * 'a -> 'a) -> 'a -> 'a tree -> 'a
将此与treefold_preorder
的比较:
('a * 'b -> 'b) -> 'b -> 'a tree -> 'b
因此,List.foldl
是:
('a * 'b -> 'b) -> 'b -> 'a list -> 'b
这允许累加函数产生任意类型'b
的值,而不是仅能够产生树的节点类型'a
的值。这种大概的偶然变化是由于将g
的输出反馈给自己造成的:
g(g(tree..., x), tree...)
强制其输入值(节点类型'a
)与其输出值具有相同的类型。
我在做什么错了?
您以错误的方式将对treeReduce
的左右调用粘在一起,并且您对g
的一次调用过多(试图将对{ {1}}),当您希望它具有类型treeReduce
或类似名称时,使其具有类型'a * 'a -> 'a
。
由于您要折叠树木,因此可能很有趣: