SML:带有基数和合成函数的树约简

时间:2019-02-27 22:24:49

标签: tree reduce sml folding

我想用一个基本值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)

但是,这不能产生正确的答案。我在做什么错了?

1 个答案:

答案 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 来更准确地为每个计算命名。

  • 让我感到奇怪的是,z1az1b都基于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


由于您要折叠树木,因此可能很有趣: