This question already has an answer here:
Output is truncated with #-signs in the REPL
(1 answer)
Closed 4 years ago.
I have a function, that creates a new tree, based on an old one, and the min/max values of each node from the old one. using the datatypes:
datatype 'a Tree = LEAF of 'a | NODE of ('a Tree) * ('a Tree)
and
datatype 'a myTree = myLEAF of 'a | myNODE of 'a*'a*('a myTree)*('a myTree)
for instance,
(NODE(NODE(NODE(LEAF(0),LEAF(9)),LEAF(6)),NODE(LEAF(3),LEAF(10))))
should produce:
(myNODE(0,10,myNODE(0,9,myNODE(0,9,myLEAF(0),myLEAF(9)),myLEAF(6)),myNODE(3,10,myLEAF(3),myLEAF(10))))
Everything seems to work. Except, the values in the leaf and internal nodes are replaced with '#'.
example:
minmaxTree t1;
val it =
myNODE (1,2,myNODE (1,2,myNODE #,myLEAF #),myNODE (1,2,myNODE #,myNODE #))
: int myTree
Im confused why the sml compiler is replacing with '#', where the values are clearly ints.
Thank you kindly!
As pointed out by molbdnilo, this was a duplicate question, the answer to my question is found here: here
There was an output restriction, the compiler was not set to print out in depth, as i need it to. after applying the solution here,
my output is:
- minmaxTree t1;
val it =
myNODE
(1,2,myNODE (1,2,myNODE (1,2,myLEAF 1,myLEAF 2),myLEAF 1),
myNODE
(1,2,myNODE (1,2,myLEAF 1,myLEAF 2),
myNODE (1,2,myNODE (1,2,myLEAF 1,myLEAF 2),myLEAF 1))) : int myTree
Related
I have a datatype in this way
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 *)
so an example for correct tree would be:
val tree1 =
Node(Node(Node(Leaf 47, 1, 1, Leaf 38),
2,1,
Leaf 55),
3,2,
Node(Leaf 27, 1, 1, Leaf 96))
and an example for violating tree would be
val tree1false =
Node(Node(Node(Leaf 47, 1, 1, Leaf 38),
2,1,
Leaf 55),
4,2,
Node(Leaf 27, 1, 1, Leaf 96))
How can I write a predicate test such that
- test tree1;
val it = true : bool
- test tree1false;
val it = false : bool
This is a recursive problem. Before solving recursive problems on trees, it is a good idea to have a firm grasp on recursion on lists. You could say that trees are generalisations of lists, or that lists are special-cases of trees: lists have one tail, trees can have any number of tails depending on the type of tree. So here is how you could reconstruct and solve the problem using lists:
If, instead of the typical list definition, you have a list that also memoizes its own length:
(* datatype 'a list = [] | :: of 'a * 'a list *)
datatype 'a lenlist = Nil | Cons of int * 'a * 'a lenlist
Then you can test that the stored length is in accordance with the actual number of values.
I'll start by creating a function that counts to illustrate the part of the function that performs recursion:
(* For regular built-in lists *)
fun count0 [] = 0
| count0 (x::xs) = 1 + count0 xs
(* Counting the memoized list type disregarding the n *)
fun count1 Nil = 0
| count1 (Cons (n, x, xs)) = 1 + count1 xs
The next part is that I'd like, in each recursive step, to test that the stored number n is also in accordance with the actual counting. What is the return type of this function? Well, the test function that you want should be 'a lenlist -> bool and the count function that I made is 'a lenlist -> int.
I will suggest that you make a testcount that kinda does both. But you can do so in many ways, e.g. by giving it "extra arguments", or by giving it "extra return values". I will demonstrate both, just to show that sometimes one is better than the other and experience will tell you which.
Here is a val testcount1 : 'a lenlist -> bool * int function:
fun testcount1 Nil = (true, 0)
| testcount1 (Cons (n, x, xs)) =
let val (good_so_far, m) = testcount1 xs
val still_good = good_so_far andalso n = m + 1
in (still_good, m + 1)
end
val goodList = Cons (4, #"c", Cons (3, #"o", Cons (2, #"o", Cons (1, #"l", Nil))))
val badList = Cons (3, #"d", Cons (2, #"e", Cons (1, #"r", Cons (0, #"p", Nil))))
Testing this,
- testcount1 goodList;
> val it = (true, 4) : bool * int
- testcount1 badList;
> val it = (false, 4) : bool * int
This shows that testcount1 returns whether the numbers add up and the list's actual length, which was necessary during recursion to test that the numbers add up in each step, but in the end is no longer necessary. You could wrap this testcount function up in a simpler test function that only cares about the bool:
fun test xs = #1 (testcount1 xs)
Here is another way to go about: There is something not so satisfying with the way testcount1 recurses. It keeps calculating the m + 1s even though it is able to determine that a list (e.g. at Cons (0, #"p", Nil)) is broken.
Here is an alternate val testcount2 : 'a lenlist * int -> bool that stores a number in an extra argument instead:
fun testcount2 (Nil, 0) = true
| testcount2 (Nil, _) = false
| testcount2 (Cons (n, x, xs), m) =
n = m andalso testcount2 (xs, m - 1)
This seems a lot neater to me: The function is tail-recursive, and it stops immediately when it senses that something is fishy. So it doesn't need to traverse the entire list if it's broken at the head. The downside is that it needs to know the length, which we don't know yet. But we can compensate by assuming that whatever is advertised is correct until it's clearly the case, or not.
Testing this function, you need to not only give it a goodList or a badList but also an m:
- testcount2 (goodList, 4);
> val it = true : bool
- testcount2 (badList, 4);
> val it = false : bool
- testcount2 (badList, 3);
> val it = false : bool
It's important that this function doesn't just compare n = m, since in badList, that'd result in agreeing that badList is 3 elements long, since n = m is true for each iteration in all Cons cases. This is helped in the two Nil cases that require us to have reached 0 and not e.g. ~1 as is the case for badList.
This function can also be wrapped inside test to hide the fact that we feed it an extra argument derived from the 'a lenlist itself:
fun size Nil = 0
| size (Cons (n, _, _)) = n
fun test xs = testcount2 (xs, size xs)
Some morals so far:
Sometimes it is necessary to create helper functions to solve your initial problem.
Those helper functions are not restricted to have the same type signature as the function you deliver (whether this is for an exercise in school, or for an external API/library).
Sometimes it helps to extend the type that your function returns.
Sometimes it helps to extend the arguments of your functions.
Just because your task is "Write a function foo -> bar", this does not mean that you cannot create this by composing functions that return a great deal more or less than foo or bar.
Now, for some hints for solving this on binary trees:
Repeating the data type,
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 *)
You can start by constructing a skeleton for your function based on the ideas above:
fun testcount3 (Leaf x, ...) = ...
| testcount3 (Leaf x, ...) = ...
| testcount3 (Node (left, leftC, rightC, right), ...) = ...
I've embedded som hints here:
Your solution should probably contain pattern matches against Leaf x and Node (left, leftC, rightC, right). And given the "extra argument" type of solution (which at least proved nice for lists, but we'll see) needed two Leaf x cases. Why was that?
If, in the case of lists, the "extra argument" m represents the expected length of the list, then what would an "extra argument" represent in the case of trees? You can't say "it's the length of the list", since it's a tree. How do you capture the part where a tree branches?
If this is still too difficult, consider solving the problem for lists without copy-pasting. That is, you're allowed to look at the solutions in this answer (but try not to), but you're not allowed to copy-paste code. You have to type it if you want to copy it.
As a start, try to define the helper function size that was used to produce test from testcount2, but for trees. So maybe call it sizeTree to avoid the name overlap, but other than that, try and make it resemble. Here's a skeleton:
fun sizeTree (Leaf x) = ...
| sizeTree (Node (left, leftC, rightC, right)) = ...
Sticking testcount3 and sizeTree together, once written, should be easy as tau.
I have the two datatypes:
datatype 'a Tree = LEAF of 'a | NODE of ('a Tree) * ('a Tree)
and
datatype 'a myTree = myLEAF of 'a | myNODE of 'a * 'a * 'a myTree * 'a myTree
With these two, I need to be able to find the min and max values of a tree.
For example:
findMin (NODE(NODE(LEAF(5),NODE(LEAF(6),LEAF(8))),LEAF(4)))
will produce 4.
I have been working on this for some time now, and I'm quite confused.
Any guidance would be helpful. Thank you.
You know that there is at least one element in every 'a Tree, so there is always a min/max.
Use pattern matching on each of the two constructors LEAF and NODE, and use recursion in the NODE case, since the two branches might have different min/max values and the min/max for the node is determined by whatever is min/max for its branches. And use the built-in helper functions Int.min and Int.max, if you're finding the min/max integers of a tree. (Your example suggests that this is the case.)
fun findMin (LEAF x) = (* ... *)
| findMin (NODE (leftTree, rightTree)) =
let (* ... use findMin recursively on each branch ... *)
in (* ... find the minimal value of the two branches ... *)
end
I'm not sure what the 'a myTree type is good for: It is a binary tree in that it has two 'a myTree branches per node, but it also has two 'a elements per node? Should you be interested in finding the min/max of either of those values? Or is one a key and another a value in some tree-based dictionary structure? If so, then why is it 'a -> 'a and not 'a -> 'b? It is hard to solve a problem when you don't understand the problem statement, and the datatype is a large portion of that.
Edit: Since you've provided a solution yourself, let me give some feedback on it:
fun findMin (LEAF(v)) = v
| findMin (NODE(left, right)) =
if findMin(left) < findMin(right)
then findMin(left)
else findMin(right)
This solution is very inefficient since it calls itself three times for each node's entire subtree. That means the number of function calls roughly follows the recurrence relation f(0) = 1 and f(n) = 3 ⋅ f(n-1). This is equivalent to 3n or exponentially many calls to find the minimal element in a list of n elements.
Here is a way that take linear time by temporarily storing the result you use twice:
fun findMin (LEAF v) = v
| findMin (NODE (left, right)) =
let val minLeft = findMin left
val minRight = findMin right
in if minLeft < minRight then minLeft else minRight
end
There is no reason to perform the Herculean task of calculating findMin left and findMin right more than once in every node of the tree. Since we refer to it multiple time, a let-in-end is an easy way to bind the results to lexically scoped names, minLeft and minRight.
The expression if minLeft < minRight then minLeft else minRight actually has a name in the standard library: Int.min. So we could do:
fun findMin (LEAF v) = v
| findMin (NODE (left, right)) =
let val minLeft = findMin left
val minRight = findMin right
in Int.min (minLeft, minRight)
end
But the reason for using a let-in-end has actually evaporated, since, with the help of a library function, we're now only referring to findMin left (aka minLeft) and findMin right (aka minRight) once now. (Actually, we are referring to them more than once, but that is inside Int.min in which the result has also been bound to a temporary, lexically scoped name.)
So we ditch the let-in-end for a much shorter:
fun findMin (LEAF v) = v
| findMin (NODE (left, right)) = Int.min (findMin left, findMin right)
In any case, these are all equally optimal: They use only n recursive function calls for n elements in the tree, which is the least you can do when the elements aren't sorted. Now, if you knew the smaller elements were always to the left, you'd have a binary search tree and you could find the min/max much faster. :-)
Edit (again): Just for fun, you could find the min/max simultaneously:
fun findMinMax (LEAF v) = (v, v)
| findMinMax (NODE (left, right)) =
let val (minLeft, maxLeft) = findMinMax left
val (minRight, maxRight) = findMinMax right
in (Int.min (minLeft, minRight), Int.max(maxLeft, maxRight))
end
I think one problem is that you're thinking hard about how to traverse the tree and check all the nodes in some order and keep track of things, but recursion will handle that for you.
Your tree has two cases; it is either a leaf, or a node with two subtrees.
This suggests that the solution will also have two cases: one for leaves and one for internal nodes.
Write down (in your own words, not code) how you would find the minimum in
a leaf; and
an internal node if you already knew the respective minimums of its subtrees -- don't worry about how to find them yet, but pretend that you know what they are.
Then write down how you find the minimums of the subtrees of an internal node.
(This is a recursion, so you've already solved this problem, before you started thinking about it.)
Then you translate it into ML.
I was 100% just overthinking the problem too much. Thank you both for your help! I got my answer.
fun findMin (LEAF(v)) = v
| findMin (NODE(left, right)) =
if findMin(left) < findMin(right)
then findMin(left)
else findMin(right)
fun findMax (LEAF(v)) = v
| findMax (NODE(left, right)) =
if findMax(left) > findMax(right)
then findMax(left)
else findMax(right)
I want to make function maptree with standard ML.
If function f(x) = x + 1;
then
maptree(f, NODE(NODE(LEAF 1,LEAF 2),LEAF 3));
should make result
NODE(NODE(LEAF 2,LEAF 3),LEAF 4))
I write the code like below.
datatype 'a tree = LEAF of 'a | NODE of 'a tree * 'a tree;
fun f(x) = x + 1;
fun maptree(f, NODE(X, Y)) = NODE(maptree(f, X), maptree(f, Y))
| maptree(f, LEAF(X)) = LEAF(f X);
but when I execute this code like this
maptree(f, (NODE(NODE(LEAF 1,LEAF 2),LEAF 3)));
result is not I want to
(NODE(NODE(LEAF 2,LEAF 3),LEAF 4)))
but
NODE(NODE(LEAF #,LEAF #),LEAF 4)).
Why this happened(not a number but #)?
# is used by the REPL when the data structure it prints is deeper than a pre-set value. If you increase that value, you'll get the result you excepted. I assume you're using SML/NJ, which calls that setting print.depth:
sml -Cprint.depth=20
- maptree(f, (NODE(NODE(LEAF 1,LEAF 2),LEAF 3)));
val it = NODE (NODE (LEAF 2,LEAF 3),LEAF 4) : int tree
You can find more options like these by executing sml -H. Look them up under the "compiler print settings" section:
compiler print settings:
print.depth (max print depth)
print.length (max print length)
print.string-depth (max string print depth)
print.intinf-depth (max IntInf.int print depth)
print.loop (print loop)
print.signatures (max signature expansion depth)
print.opens (print `open')
print.linewidth (line-width hint for pretty printer)
Some comments:
I would probably go with the definition
datatype 'a tree = Leaf | Node of 'a tree * 'a * 'a tree
so that trees with zero or two elements can also be expressed.
I would probably curry the tree map function
fun treemap f Leaf = Leaf
| treemap f (Node (l, x, r)) = Node (treemap f l, x, treemap f r)
since you can then partially apply it, e.g. like:
(* 'abstree t' returns t where all numbers are made positive *)
val abstree = treemap Int.abs
(* 'makeFullTree n' returns a full binary tree of size n *)
fun makeFullTree 0 = Leaf
| makeFullTree n =
let val subtree = makeFullTree (n-1)
in Node (subtree, n, subtree)
end
(* 'treetree t' makes an int tree into a tree of full trees! *)
val treetree = treemap makeFullTree
You may at some point want to fold a tree, too.
I’m very new to OCaml and having a difficult time implementing a series of functions to build a T9 predictive text program. For example if my word is “Dog” - as an integer list would be [3;6;4]. I already have a pattern matching function to relate words to int lists. I’m using the data type trie to map numbers to the possible word outcomes possible:
type ('a, 'b) trie = Node of 'b list * ('a * ('a, 'b) trie) list
A trie with edges labelled with keys of type 'a and nodes labeled with lists of words of type 'b
I need to write a function with parameters trie and edge label that returns a trie at the end of the edge.
val trie_of_key : (’a, ’b) trie -> ’a -> (’a, ’b) trie = <fun>
How do I traverse the edges to arrive at a given node? Functional programming is still disorienting to me, so I am unsure of the recursive steps needed to arrive at the expected sub-trie.
It seems to me that if you don't want to modify the trie, functional programming is the same as regular old imperative programming. A lookup function that doesn't do any restructuring along the way should be pretty straightforward. Maybe you're just overthinking the problem?
It's hard to say more without seeing an example of what you've tried.
Update
Here's a lookup function I just wrote for a B-Tree structure. There are some similarities to the problem you're trying to solve, so maybe it will give you some ideas.
type ('a, 'b) btree = Node of ('a * 'b) list * ('a, 'b) btree list
let rec lookup bt k =
match bt with
| Node ([], _) -> raise Not_found
| Node (keyvals, subtrees) ->
let rec look kvs sts =
match kvs with
| [] ->
lookup (List.hd sts) k (* Rightmost subtree *)
| (hdk, hdv) :: tlkv ->
if hdk = k then hdv
else if hdk < k then look tlkv (List.tl sts)
else lookup (List.hd sts) k
in
look keyvals subtrees
I don't think the details are important, but if you're trying to understand the code carefully, it's based on the invariant that a node with no key/value pairs is a leaf node with no subtrees. Otherwise if there are n key/value pairs in the node, there are exactly n + 1 subtrees. (These subtrees can be empty.)
Where let's say:
datatype bin_tree = Empty |
Node of value * bin_tree * bin_tree
How would I go about filling a binary tree (not a binary search tree where left is smaller than root and right bigger). Just values from a list inserted at each node in a binary tree.
You use the value constructors you've declared.
If we assume for a moment that value is int instead, then we for instance have that the tree
1
/ \
2 4
/
3
is represented by:
Node (1,
Node (2,
Node (3, Empty, Empty),
Empty
),
Node (4, Empty, Empty)
)
Or, equivalently, on one line:
Node (1, Node (2, Node (3, Empty, Empty), Empty), Node (4, Empty, Empty))
It's not really possible to help you, without knowing more about how you wan't your tree constructed from a given list. However here is an example that creates a balanced tree. It takes the first element and uses it as the node value, and then it splits the rest of the list into two sub lists of equal size (if possible), by taking all "even" element in the "left" list and all "odd" elements in the "right" list:
datatype 'a bin_tree = Empty
| Node of 'a * 'a bin_tree * 'a bin_tree
fun list_split xs =
let
fun loop [] (left, right) = (rev left, rev right)
| loop (x::y::xs) (left, right) = loop xs (x :: left, y :: right)
| loop (x :: xs) (left, right) = loop xs (x :: left, right)
in
loop xs ([], [])
end
fun built_tree [] = Empty
| built_tree (x :: xs) =
let
val (left, right) = list_split xs
val left_tree = built_tree left
val right_tree = built_tree right
in
Node (x, left_tree, right_tree)
end
The result:
- built_tree [1,2,3,4,5,6,7,8,9];
val it =
Node
(1,Node (2,Node (4,Node (8,Empty,Empty),Empty),Node (6,Empty,Empty)),
Node (3,Node (5,Node (9,Empty,Empty),Empty),Node (7,Empty,Empty)))
: int bin_tree
Here is an answer to the same question done in Java. This will probably help a good bit :).