Fold with Trees

Speaking of recursing other data structures, here's how we could program a fold over a binary tree. Here's our tree data structure:

type 'a tree = 
| Leaf 
| Node of 'a * 'a tree * 'a tree

Let's develop a fold functional for 'a tree similar to our fold_right over 'a list. Recall what we said above: "One way to think of fold_right would be that the [] value in the list gets replaced by init, and each :: constructor gets replaced by op. For example, [a;b;c] is just syntactic sugar for a::(b::(c::[])). So if we replace [] with 0 and :: with (+), we get a+(b+(c+0))." Here's a way we could rewrite fold_right that will help us think a little more clearly:

type 'a list =
  | Nil 
  | Cons of 'a * 'a list

let rec foldlist init op = function
  | Nil -> init
  | Cons (h,t) -> op h (foldlist init op t)

All we've done is to change the definition of lists to use constructors written with alphabetic characters instead of punctuation, and to change the argument order of the fold function.

For trees, we'll want the initial value to replace each Leaf constructor, just like it replaced [] in lists. And we'll want each Node constructor to be replaced by the operator. But now the operator will need to be ternary instead of binary—that is, it will need to take three arguments instead of two—because a tree node has a value, a left child, and a right child, whereas a list cons had only a head and a tail.

Inspired by those observations, here is the fold function on trees:

let rec foldtree init op = function
  | Leaf -> init
  | Node (v,l,r) -> op v (foldtree init op l) (foldtree init op r)

If you compare that function to foldlist, you'll note it very nearly identical. There's just one more recursive call in the second pattern-matching branch, corresponding to the one more occurrence of 'a tree in the definition of that type.

We can then use foldtree to implement some of the tree functions we've previously seen:

let size t = foldtree 0 (fun _ l r -> 1 + l + r) t
let depth t = foldtree 0 (fun _ l r -> 1 + max l r) t
let preorder t = foldtree [] (fun x l r -> [x] @ l @ r) t

results matching ""

    No results matching ""