Ana RamÃrez Chang
CS 302
Assignment 5
Problem Statement
Write a function treefold, similar to foldr that takes a combination function, a base value and a tree. Use the following datatype for a tree with an arbitrary branching factor.
datatype 'a tree = Tree of 'a * 'a tree list
A tree consists of an element and a list of subtrees. For example, the value
val tr: int tree = Tree(3, [Tree(2, [Tree(8, nil), Tree(5, nil), Tree(7, [Tree(11, nil), Tree(9, nil)])]), Tree(6, nil)]);
represents the tree
Exercises |
|
Preparation | The reader should be able to use foldr, understand what a tree is and the datatype in the problem statement, undersand let expressions and understand curried functions. |
Understanding treefold
What can you use foldr to do? | foldr abstracts out the recursion necessary to traverse a list. You can implement any recursive function over a list with foldr (as long as the order the list is recursed in doesn't matter or the order is from right to left.) Some examples include:
|
What is the type of foldr? | foldr folds an 'a list into a value of type 'b. At each step, it combines the head element in the list with the result so far. So the type of the combination function is ('a * 'b -> 'b). foldr also needs a value of type 'b to combine with the first element in the list. So foldr takes a combination function of type ('a * 'b -> 'b), a base value of type 'b, and an 'a list and returns a value of type 'b. foldr: ('a * 'b -> 'b) -> 'b -> 'a list -> 'b |
Stop and Practice-> | Implement a few functions using foldr. |
What can treefold be used for? | Just like foldr, treefold also abstracts out recursion, but instead of abstracting out the recursion to recurse a list, it abstracts out the recursion to recurse a tree. You can implement any recursive function over a tree that recurses the tree in the same order as your treefold function. For example:
|
Stop and Predict -> | What is the type of treefold. |
What is the type of treefold? | treefold: ('a * 'b -> 'b) -> 'b -> 'a tree -> 'b |
Stop and Practice-> | Implement a few functions using treefold. |
Implementing treefold
How can we break the problem into smaller pieces? | Since treefold abstracts out the recursion over a tree, we can break it down into the base case and the recursive case. |
What will the skeletin of treefold look like? | For the skeletin, just lay out the base case and the recursive case without implementing eithr of them. This way you will have parameter variable names to refer to in your thinking about the solution. fun treefold f base Tree(elt, nil) = ... | treefold f base Tree(elt, subTreeList) = ... |
What does the base case look like? (pseudo code for now) | In the base case we don't have any more recursing to do, so we just need to apply the combination function to the elt and base. fun treefold f base Tree(elt, nil) = apply f to base and elt |
Stop and Participate -> | Write the code for the base case. |
What does the recursive case look like? | In the recursive case, we need to recurse over all the sub trees. So we need to apply the combination function to the current element and the result so far (base) and use the result as the new base as we recurse over the subtrees. | treefold f base Tree(elt, subTreeList) = apply f to base and elt and use the result as the new base as you fold all the subtrees together. |
How can we fold the sub trees together? | Our treefold function can fold a tree, but we need to fold a list of trees together. |
How do we fold a list of trees together? | We know how to fold a tree ad we have a list of trees, so we can use foldr to fold the sub trees together. |
What arguments should we pass to foldr? | Lets look at the types. We have an 'a tree list and we want to get a value of type 'b. First, we should rewrite the type of foldr with different letters for the polymorphic types so we don't confuse them with the polymorphic types in treefold ('a and 'b). foldr: ('m * 'n -> 'n) -> 'n -> 'm list -> 'n |
Stop and Predict -> | If we have an 'a tree list, what type will 'm be when we use foldr to fold our 'a tree list? |
What is the type of foldr for this specific use? |
foldr: ('m * 'n -> 'n) -> 'n -> 'm list -> 'n foldr: ('a tree * 'b -> 'b) -> 'b -> 'a tree list -> 'b |
Which arguments for foldr do we already have? | We already have the base case of type 'b (from applying f to elt and base). We have an 'a tree list (subTreeList) |
Which arguments do we still need? | We need a function of type ('a tree * 'b -> 'b) that folds an 'a tree into a value of type 'b using the base valeu of type 'b. |
How can we fold a tree? | Well, treefold will fold a tree, we just need to lign up the types. treefold: ('a * 'b -> 'b) -> 'b -> 'a tree -> 'b |
Which arguments do we have? | f has type ('a * 'b -> 'b) |
What is left? | We still need a function of type ('a tree * 'b -> 'b) and we have the following that we haven't filled in our call to treefold: 'b -> 'a tree -> 'b. These are very similar, we just need to fix the argument order and uncurry the leftover part from treefold to pass it into foldr. |
How do we manipulate treefold to pass it into foldr? | We need a function with parameters 'a tree and 'b, so start there. fun treefoldWrapper(tr, b) = ... Now use treefold and f to implement it. fun treefoldWrapper(tr, b) = treefold f b tr |
What are the final arguments to foldr? | foldr treefoldWrapper (f(elt, base)) subTreeList |
Stop and Participate -> | Write the code for the recursive case. |
How does it all come together? | fun treefold f base Tree(elt, nil) = f(elt, base) | treefold f base Tree(elt, subTreeList) = let val fun treefoldWrapper (tr, b) = treefold f b tr in foldr treefoldWrapper (f(elt, base)) subTreeList end |
Stop and Participate -> | Test treefold by using it in the example you implemented above (when we asked you to use treefold to implement one of the examples). |