Standard ML Binary Tree Traversal - binary-tree

I am new to SML and doing a practice about tree traversal.
This is the setting of question.
datatype 'a bTree = nil | bt of 'a bTree * 'a * 'a bTree;
I need to write a function inorder which accepts a binary tree and return a lists of all members of the tree in inorder traversal.
I wrote this line:
fun inorder(nil) = nil
| inorder(bt(left,key,right)) = inorder(left) # [key] # inorder(right);
But get some error and don't know how to fix:
Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z list * 'Z list
operand: 'Z list * 'Y bTree
in expression:
(key :: nil) # inorder right
Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z list * 'Z list
operand: 'Y bTree * _
in expression:
inorder left # (key :: nil) # inorder right

You've inadvertently hidden the nil list constructor and replaced it with your tree constructor of the same name.
This means that your first case,
inorder(nil) = nil
says that the result of inorder is a tree; its type is
'a bTree -> 'a bTree
and you can't append (#) a list to a 'a bTree.
Your code will work if you rename the empty tree constructor:
datatype 'a bTree = nilTree | bt of 'a bTree * 'a * 'a bTree;
fun inorder nilTree = nil
| inorder (bt(left,key,right)) = inorder left # [key] # inorder right;
or use [] instead of nil.
Not hiding nil is the better solution, though.

Related

SML: Counting nodes

My assignment is to write a function that will compute the size of a binary tree. This is the implementation of the tree structure:
datatype 'a bin_tree =
Leaf of 'a
| Node of 'a bin_tree (* left tree *)
* int (* size of left tree *)
* int (* size of right tree *)
* 'a bin_tree (* right tree *)
I was given this template from my professor:
fun getSize Empty = 0
| getSize (Leaf _) = 1
| getSize (Node(t1,_,t2)) = getSize t1 + getSize t2;
I was wondering if I need to manipulate this to agree with my tree structure in order to get it to work?
The 'a bin_tree type memoizes the size of each sub-tree. So if you're allowed to assume that the size that is stored is correct, you can return the size of a tree without recursion.
The template given by your professor is not for this type, but for another tree type that does not memoize the size. It demonstrates how you can calculate the size for such a tree by pattern matching and recursion, both language features of which you need to also use.
So the task is for you to write an entirely different function for the 'a bin_tree type. You have to figure out what the right way to pattern match is. First off, the template for getSize does not add up: There are three cases with three constructors, Empty, Leaf x and Node (L, x, R). But the 'a bin_tree type only has two constructors, Leaf x and Node (L, sizeL, sizeR, R).
So you want to read up on how to perform pattern matching on data types.

Find character in tree with SML

I'm new to SML and trying to wrap my head around functional programming. I want to have a function that accepts a tree t and a character c and returns true or false if the tree contains the character.
The algorithm I want to implement is:
if leaf is null return false,
else if character is in leaf return true,
return result of left tree or result of right tree
This is my tree datatype
datatype 'a tree =
Leaf of 'a
| Node of 'a tree * 'a * 'a tree;
And this is the function
fun containsChar (Leaf t, c: char) = false
| containsChar (Node (left, t, right)) =
if t = c then true else false
| containsChar (Node (left, t, right)) = (containsChar left) <> (containsChar right);
I am getting Unbound value identifier "c". Why is this?
There is nothing called "c" in that clause. There is a "c" in the leaf case, but that's a completely different case. You forgot that parameter in the other cases.
(And if t = c then true else false is equivalent to t = c.)
You also have identical patterns in the second and third clauses, which isn't going to work.
Another problem you have is the "leaf is null" rule – a leaf can't be "null".
I suspect that this is what brought you astray, as the result of your first clause is false even though the argument is clearly an existing leaf, and your second clause is clearly not a leaf but looks like your second rule.
Your rules should be these:
A tree contains a character if and only if
it is the value in a leaf, or
it is the value in a node, or
it is contained in a node's subtrees.
In ML (removing the restriction to char Tree since it seems arbitrary),
fun contains (Leaf t, c) = t = c
| contains (Node (left, t, right), c) = t = c
orelse contains(left, c)
orelse contains(right, c)
You could generalise the function once more to
fun any p Leaf = false
| any p (Node (left, x, right)) =
p x orelse any p left orelse any p right
fun contains c t = any (fn x => c = x) t

Standard ML polymorphic sorting

I am very inexperienced in ML, and I just can't make sense of this.
Start question
Polymorphic Sorting
This function performing insertion sort on a list takes as arguments a comparison function less and a list l of elements to be sorted. The code compiles and runs correctly:
fun sort(less, nil) = nil |
sort(less, a : : l) =
let
fun insert(a, nil) = a : : nil |
insert(a, b : : l) = if less(a,b) then a : : (b: : l)
else b : : insert(a, l)
in
insert(a, sort(less, l))
end;
What is the type of this sort function? Explain briefly, including the type of the subsidiary function insert. You do not have to run the ML algorithm on this code; just explain why an ordinary ML programmer would expect the code to have this type. (End of question)
I've gotten the type of the sort function (by running the code in an SML interpreter), but I just can't get the second part about insert.
Type of sort function:
val sort = fn : ('a * 'a -> bool) * 'a list -> 'a list
Any help would be greatly appreciated.
That you figured out the type of sort by "cheating" makes the next step harder; don't take shortcuts.
(Nobody ever learned anything by peeking at the answer.)
But here's how you could figure out insert:
You know from
val sort = fn : ('a * 'a -> bool) * 'a list -> 'a list
that the second argument to sort is an 'a list.
In
insert(a, sort(less, l))
you can see immediately that it has some type (X * Y) -> Z for some X, Y, and Z.
You're passing the first element of sort's second argument - a - as insert's first argument.
Since sort's second argument is an 'a list, that list's first element is an 'a.
So X is 'a, and we now know that insert is ('a * Y) -> Z for some Y and Z.
The type of insert's second argument - sort(less, l) - is well known; it's 'a list.
So we now know that Y is 'a list, and insert is ('a * 'a list) -> Z for some Z.
All that remains is the return type, and since
insert(a, sort(less, l))
is what sort returns, it must have the same return type as sort.
So Z is 'a list.
In summary, insert's type is
('a * 'a list) -> 'a list

Find the deepest element of a Binary Tree in SML

This is a homework question.
My question is simple: Write a function btree_deepest of type 'a btree -> 'a list that returns the list of the deepest elements of the tree. If the tree is empty, then deepest should return []. If there are multiple elements of the input tree at the same maximal depth, then deepest should return a list containing those deepest elements, ordered according to a preorder traversal. Your function must use the provided btree_reduce function and must not be recursive.
Here is my code:
(* Binary tree datatype. *)
datatype 'a btree = Leaf | Node of 'a btree * 'a * 'a btree
(* A reduction function. *)
(* btree_reduce : ('b * 'a * 'b -> 'b) -> 'b -> 'a tree -> 'b) *)
fun btree_reduce f b bt =
case bt of
Leaf => b
| Node (l, x, r) => f (btree_reduce f b l, x, btree_reduce f b r)
(* btree_size : 'a btree -> int *)
fun btree_size bt =
btree_reduce (fn(x,a,y) => x+a+y) 1 bt
(* btree_height : 'a btree -> int *)
fun btree_height bt =
btree_reduce (fn(l,n,r) => Int.max(l, r)+1) 0 bt
I know that I have to create a function to pass to btree_reduce to build the list of deepest elements and that is where I am faltering.
If I were allowed to use recursion then I would just compare the heights of the left and right node then recurse on whichever branch was higher (or recurse on both if they were the same height) then return the current element when the height is zero and throw these elements into a list.
I think I just need a push in the right direction to get started...
Thanks!
Update:
Here is an attempt at a solution that doesn't compile:
fun btree_deepest bt =
let
val (returnMe, height) = btree_reduce (fn((left_ele, left_dep),n,(right_ele, right_dep)) =>
if left_dep = right_dep
then
if left_dep = 0
then ([n], 1)
else ([left_ele::right_ele], left_dep + 1)
else
if left_dep > right_dep
then (left_ele, left_dep+1)
else (right_ele, right_dep+1)
)
([], 0) bt
in
returnMe
end
In order to get the elements of maximum depth, you will need to keep track of two things simultaneously for every subtree visited by btree_reduce: The maximum depth of that subtree, and the elements found at that depth. Wrap this information up in some data structure, and you have your type 'b (according to btree_reduce's signature).
Now, when you need to combine two subtree results in the function you provide to btree_reduce, you have three possible cases: "Left" sub-result is "deeper", "less deep", or "of equal depth" to the "right" sub-result. Remember that the sub-result represent the depths and node values of the deepest nodes in each subtree, and think about how to combine them to gain the depth and the values of the deepest nodes for the current tree.
If you need more pointers, I have an implementation of btree_deepest ready which I'm just itching to share; I've not posted it yet since you specifically (and honorably) asked for hints, not the solution.
Took a look at your code; it looks like there is some confusion based on whether X_ele are single elements or lists, which causes the type error. Try using the "#" operator in your first 'else' branch above:
if left_dep = 0
then ([n], 1)
else (left_ele # right_ele, left_dep + 1)

Haskell Binary Tree Function (map)

How can I define a Haskell function which will apply a function to every value in a binary tree? So I know that it is similar to the map function - and that its type would be:
mapT :: (a -> b) -> Tree a -> Tree b
But thats about it...
You can declare an instance of class Functor. This is a standard class for data types which allow a function to be mapped over. Please note how similar the type of fmap is to your mapT's type:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Let's assume your tree is defined as
data Tree a = Node (Tree a) (Tree a) | Leaf a
deriving (Show)
Then you can declare an instance of Functor this way:
instance Functor Tree where
fmap f (Node l r) = Node (fmap f l) (fmap f r)
fmap f (Leaf x) = Leaf (f x)
This is how you can use it:
main = do
let t = Node (Node (Leaf 1) (Leaf 2)) (Leaf 3)
let f = show . (2^)
putStrLn $ "Old Tree: " ++ (show t)
putStrLn $ "New Tree: " ++ (show . fmap f $ t)
Output:
Old Tree: Node (Node (Leaf 1) (Leaf 2)) (Leaf 3)
New Tree: Node (Node (Leaf "2") (Leaf "4")) (Leaf "8")
You can also define for convenience:
mapT = fmap
Surely, you can do it without type classes, but it makes the code more readable for the others if you use standard functions (everyone knows the usual behaviour of fmap).
I'll pretend this is homework and not give away all of the answer. If I'm mistaken, my apologies.
Probably your Tree type looks something like this:
data Tree a = TreeNode a (Tree a) (Tree a) | EmptyNode
There are two cases here, and you will need to write a mapT implementation for each of them:
An internal node, TreeNode, which carries a value of type a and has a left and a right child. What needs to be done in this case?
A terminal node, EmptyNode. What needs to be done in this case?
The basic format of the map function applies to both. Let's look at the definition of the map function for lists:
map f (x:xs) = f x : map f xs
map _ [] = []
We can generalize this like so:
You take the first value in the data structure
Apply the function to it
Recursively call your map function with the remainder of the data structure
Pass both the modified value and the recursive call into the constructor for your type.
When you reach the end, stop recursing
All you really need is to look at your constructor and the map function should fall into place.
Interesting question if the input and output are supposed to be sorted binary trees. If you just naively traverse the tree and apply the function, the output tree may no longer be sorted. For example, consider if the function is non-linear, like
f(x) = x * x - 3 * x + 2
If the input has { 1, 2, 3, 4 } then the output will have { 2, 0, 0, 2 }. Should the output tree contain only 0 and 2?
If so, you may need to iteratively build up the output tree as you strip down and process the input tree.

Resources