Sml folding a tree

后端 未结 2 603
长发绾君心
长发绾君心 2020-12-20 07:10

I am trying to get the product of a tree by using the fold function so far this is what I have. I am confused on how to use the fold method while transversing the tree

2条回答
  •  遥遥无期
    2020-12-20 07:54

    When folding a binary tree,

    datatype 'a tree = Leaf | Branch of 'a tree * 'a * 'a tree
    

    you may traverse it in different ways. Among common strategies you have,

    (* 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
    

    which Wikipedia nicely illustrates as,

    Usage

    val treelist = treefold op:: []
    val treeproduct = treefold op* 1
    val treecount = treefold (fn (_, count) => count + 1) 0
    

    Extra

    In-order traversal isn't meaningful if each branch/node doesn't have an 'a value.

    See also how to apply tail-recursion on trees to avoid stack overflows.

    For some problems that involve tree traversal, it may be useful to supply the context of the traversal like paramorphisms do:

    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
    

    This is a slight generalisation of treefold_preorder in which f is fed the entire branch.

    This lets you e.g. find people in an ancestry tree for which a predicate holds for their subtree,

    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
    

    Another neat notion for tree traversal are zippers (LYAH chapter).

提交回复
热议问题