How do implement height of a binary search tree recursively using elixir? - recursion

I am using Elixir to write some programs for binary search trees and have run into a roadblock with a function to calculate height recursively.
The basic recursive formula for the height of a tree goes as follows.
If tree is empty then return 0
Else
Get the max depth of left subtree recursively i.e.,
call maxDepth( tree->left-subtree)
Get the max depth of right subtree recursively i.e.,
call maxDepth( tree->right-subtree)
Get the max of max depths of left and right
subtrees and add 1 to it for the current node.
max_depth = max(max dept of left subtree,max depth of right subtree) + 1
Return max_depth
For my part, I am getting the following error when I try to test out the function with a generic node structure.
** (ArithmeticError) bad argument in arithmetic expression
I tried removing the addition of 1 to left_depth and right_depth. That removed the arithmetic error but I'm also not getting any numerical result (height) to show up.
Here is my height function. As you can see, it follows the recursive format pretty much to the letter.
# calculate the height
#spec height(bst_node) :: number
def height(node) do
if is_nil(node) do
IO.puts "No tree exists. The height is 0"
else
left_depth = height(node.left)
right_depth = height(node.right)
if left_depth >= right_depth do
left_depth + 1
IO.puts "The height of the tree is #{left_depth + 1}"
else
right_depth + 1
IO.puts "The height of the tree is #{right_depth + 1}"
end
end
end
I would prefer to be able to execute this height function recursively in elixir but it is certainly not the end of the world if I have to resort to non-recursive means to get it done. This should just display the height of a generic tree.

There are three features of elixir that are very useful when implementing recursive solutions:
Parameter pattern matching
Multiple function clauses
Tail-call optimization
Here's an example solution that uses the first two features:
defmodule Tree do
defstruct [:left, :right]
def height(%Tree{left: nil, right: nil}), do: 0
def height(%Tree{left: nil, right: right}), do: 1 + height(right)
def height(%Tree{left: left, right: nil}), do: 1 + height(left)
def height(%Tree{left: left, right: right}), do: 1 + max(height(left), height(right))
end
First, define a struct called Tree with left and right to represent our tree.
Then we define 4 clauses of a height function that uses pattern matching to inspect the Tree's left and right values.
If both left and right are nil, then we are a leaf and can return height 0
If one of the children is nil, then we can return the height of the non-nil tree, plus 1 for ourself (the current node).
Same as above.
The final clause deals with the case where both children are non-nil. In that case, return the maximum of the height of the two children, plus 1 for ourself.
Note that the 1 + recursive_call() style will result in a stack of recursive calls, because it has to keep track of the height of the child nodes in the call stack in order to finally perform the 1 + operation. We can minimize this by passing the in-progress height as an acc accumulator parameter to the function, and taking advantage of tail-call optimization, which allows the compiler to reduce the number of stack frames needed when a the last thing a function does is to call itself. In this case, we still have to calculate the max of the two subtrees in the final clause, which means we're not using a tail-call in the majority of the cases, but I included it for completeness.:
def height_tailcall(%Tree{left: nil, right: nil}, acc), do: acc
def height_tailcall(%Tree{left: nil, right: right}, acc) do
height_tailcall(right, acc + 1)
end
def height_tailcall(%Tree{left: left, right: nil}, acc) do
height_tailcall(left, acc + 1)
end
def height_tailcall(%Tree{left: left, right: right}, acc) do
max(height_tailcall(left, acc + 1), height_tailcall(right, acc + 1))
end
Example:
def example do
leaf = %Tree{}
height1 = %Tree{left: leaf, right: leaf}
height2 = %Tree{left: height1, right: height1}
height3 = %Tree{left: height2, right: height1}
height4 = %Tree{left: nil, right: height3}
IO.inspect(height(leaf), label: "leaf")
IO.inspect(height(height1), label: "height1")
IO.inspect(height(height2), label: "height2")
IO.inspect(height(height3), label: "height3")
IO.inspect(height(height4), label: "height4")
IO.inspect(height_tailcall(leaf, 0), label: "leaf (tail recursion)")
IO.inspect(height_tailcall(height1, 0), label: "height1 (tail recursion)")
IO.inspect(height_tailcall(height2, 0), label: "height2 (tail recursion)")
IO.inspect(height_tailcall(height3, 0), label: "height3 (tail recursion)")
IO.inspect(height_tailcall(height4, 0), label: "height4 (tail recursion)")
height4
end
Output:
leaf: 0
height1: 1
height2: 2
height3: 3
height4: 4
leaf (tail recursion): 0
height1 (tail recursion): 1
height2 (tail recursion): 2
height3 (tail recursion): 3
height4 (tail recursion): 4
%Tree{
left: nil,
right: %Tree{
left: %Tree{
left: %Tree{
left: %Tree{left: nil, right: nil},
right: %Tree{left: nil, right: nil}
},
right: %Tree{
left: %Tree{left: nil, right: nil},
right: %Tree{left: nil, right: nil}
}
},
right: %Tree{
left: %Tree{left: nil, right: nil},
right: %Tree{left: nil, right: nil}
}
}
}

Your exception
** (ArithmeticError) bad argument in arithmetic expression
has nothing to do with your code being correct or not. The value of a block of code is, by default, the last expression evaluated inside of that block. When you say:
right_depth + 1
IO.puts "The height of the tree is #{right_depth + 1}"
Your last expression is IO.puts, so that's what gets returned from the function call.
IO.puts is your last expression and it returns an atom. Verify that with the helper i/1 in IEx:
iex(3)> i(IO.puts "Puts returns an atom")
Puts returns an atom
Term
:ok
Data type
Atom
Reference modules
Atom
:ok
Trying to add two atoms results in an invalid operation. The exact message and error can be reproduced in IEx.
iex(4)> :atom + :atom
** (ArithmeticError) bad argument in arithmetic expression: :atom + :atom
:erlang.+(:atom, :atom)

Related

How to count a number on in Elixir without built in function such as Enum.count?

How to count a number on in Elixir without built-in function such as Enum.count. Here is my code, Thanks so much
defmodule Ans do
#my_favorite_number 0
def sum([]) do
0
end
def sum([head|tail]) do
head + sum(tail)
end
def average([head|tail]) do
total = sum([head|tail])
iterations = Enum.count([head|tail])
output = total / iterations
end
end
You should read about tail-call optimization. The compiler makes use of this optimisation to prevent a new stack frame being created every recursive call, which will happen in your code. Here is an example of how to write the sum/1 function in a tail-recursive way. The main idea is to keep the return in an accumulator variable that is passed to each call, instead of building up the answer in the call stack:
def sum(list), do: sum(0, list)
def sum(acc, []), do: acc
def sum(acc, [head | tail]), do: sum(acc + head, tail)
For count, you can do something similar, but just add 1 instead of the value of the list item:
def count(list), do: count(0, list)
def count(acc, []), do: acc
def count(acc, [_head | tail]), do: count(acc + 1, tail)
While the answer by Adam is perfectly correct, to calculate the average you might do better (in one loop,) using more sophisticated accumulator.
defmodule M do
def avg(list), do: do_avg({0, 0}, list)
defp do_avg({cnt, sum}, []),
do: sum / cnt
defp do_avg({cnt, sum}, [h | t]),
do: do_avg({cnt + 1, sum + h}, t)
end
M.avg [1,2,3,4]
#⇒ 2.5
Here we do accumulate both count and total and calculate an average on the last step when the list is exhausted.
Also, you might return everything, as a tuple {cnt, sum, sum / cnt}, or as a map for better readability.

Using pattern matching and recursion in Elixir to split the list

I am new in Elixir and new in programming, especially functional programming (less than 1 year experience in Ruby and RoR). For the moment I am reading "Programming Elixir" by Dave Thomas. And I am completely stuck with one problem from the Lists and Recursion theme.
Dave asking to "implement the following Enum functions using no library functions or list comprehensions: ...split ..."
The original function is here.
I solve the problem with rather long, probably not too optimal (and seems to me partially disobeying Dave's restrictions) way:
def split(list, count) do
if count < 0, do: count = len(list) + count
list1 = filter1(list, count)
list2 = list -- list1
# list2 = filter2(list, list1)
{ list1, list2 }
end
def len([]), do: 0
def len([ _head | tail ]), do: 1 + len(tail)
defp filter1([], _count), do: []
defp filter1([ head | tail], count) do
if count > 0 do
[ head | filter1(tail, count - 1) ]
else
filter1(tail, count - 1)
end
end
Browsing through the page with Dave's and other readers solutions I find out pattern which was used by 2 or 3 readers:
def split([head | tail], count) when count > 0 do
{left, right} = split(tail, count-1)
{[head | left], right}
end
def split(list, _count), do: {[], list}
This code seems to me rather elegant, but I can not understand how it works.
I mean I've tried to comprehend what happening step by step and I failed.
I can imagine what happening in my filter1 recursive function. List is forming like this: [ head_1 | ... head_n | filter1(tail_n, count - n) ]
But I can't understand why { left, right } tuple is matching the recursive call for the function. What should match to the left and what to the right? How this recursion works?...
(The meaning of the second line (of the function) is also not clear for me but I think this is strictly connected with the first question.)
UPD:
Thanks to #Josh Petitt, #tkowal and #CodyPoll I think I moved forward in my comprehension of the case.
Now I am thinking about the recursion-matching pattern discussed in this "pyramidal way":
1 split([1, 2, 3], 2)
2 {left, right} = split([2, 3], 1)
3 {[1 | left], right}
4 {left, right} = split([3], 0)
5 {[1 | [2 | left]], right}
6 {[1 | [2 | []]], [3]}
7 {[1 ,2], [3]}
First step (line 1): call the function.
Second step (lines 2, 3): match {left, right} tuple to the recursive function call and return {[1 | left], right} tuple
Third step (lines 4, 5): match {left, right} tuple to the next recursive call and return {[1 | [2 | left]], right} tuple
Fourth step (line 6): since split([3], 0) matching the second clause we get {left, right} = {[], [3]} at this point and we can no replace left and right variables in the line 5 with [] and [3] accordingly
Fifth step (line 7): "pipes" do their job and return the list to finally match the left variable
What I still don't understand is how folks come to this type of solution? (Probably experience with both pattern matching and recursion.)
And another thing bothers me. If we take line 3 for example, it is a "return" which contains two variables. But no values was actually matched to this variables. According to my scheme this variables only match their values in line 7.
How Elixir deal with this?
Is it some implicit nil matching?
Or I am taking the process wrong and there is no actual return until the final step?
Recursion is sometimes very difficult to understand just looking at the code. Mentally tracking what is put on the stack and what and when it is retrieved can exhaust our working memory very quickly. It can be useful to draw the path of every passage in the hierarchy of the recursion tree, and this is what I've done to try to answer to your question.
To understand how things work in this example, first of all we have to recognize the existence of two distinct stages in the Clause 1, the first stage is the code executed before the recursion, the second stage is the code that will be executed after it.
(to better explain the flow, I've added some variables to the original code)
# Clause 1
def split(in_list, count) when count > 0 do
# FIRST STAGE
[head | tail] = in_list
# RECURSION
result = split(tail, count - 1)
# SECOND STAGE
{left, right} = result
return = {[head | left], right}
end
#Clause 2
def split(list, _count), do: return = {[], list}
Now, before continue to reading, please look at the code and try to answer to these questions:
after how many iterations of the first block the result variable will be bound for the first time ?
How many times the recursion split(tail, count - 1) will be called inside Clause 1 ?
How many times the Clause 2 split(list, _count) will be called?
What is the role of the Clause 2 ?
And now compare your answers looking at this schema that show every passage and its hierarchy:
(as an example, we split the list [1, 2, 3, 4, 5] after its third element to obtain the tuple {[1, 2, 3], [4, 5]})
split([1,2,3,4,5], 3)
> FIRST STAGE of CLAUSE 1 / ITERATION 1 called as: split( [1, 2, 3, 4, 5], 3 ):
Got 'head'=1, 'tail'=[2, 3, 4, 5], 'count'=3
now I'm going to iterate passing the tail [2, 3, 4, 5],
Clause 1 will match as the counter is still > 0
> FIRST STAGE of CLAUSE 1 / ITERATION 2 called as: split( [2, 3, 4, 5], 2 ):
Got 'head'=2, 'tail'=[3, 4, 5], 'count'=2
now I'm going to iterate passing the tail [3, 4, 5],
Clause 1 will match as the counter is still > 0
> FIRST STAGE of CLAUSE 1 / ITERATION 3 called as: split( [3, 4, 5], 1 ):
Got 'head'=3, 'tail'=[4, 5], 'count'=1
Now the counter is 0 so I've reached the split point,
and the Clause 2 instead of Clause 1 will match at the next iteration
> Greetings from CLAUSE 2 :-), got [4, 5], returning {[], [4, 5]}
< Im BACK to the SECOND STAGE of ITERATION 3
got result from CLAUSE 2: {[], [4, 5]}
{left, right} = {[], [4, 5]}
Now I'm build the return value as {[head | left], right},
prepending 'head' (now is 3) to the previous value
of 'left' (now is []) at each iteration,
'right' instead is always [4, 5].
So I'm returning {[3], [4, 5]} to iteration 2
< Im BACK to the SECOND STAGE of ITERATION 2
got result from previous Clause 1 / Iteration 3, : {[3], [4, 5]}
{left, right} = {[3], [4, 5]}
Now I'm build the return value as {[head | left], right},
prepending 'head' (now is 2) to the previous value
of 'left' (now is [3]) at each iteration,
'right' instead is always [4, 5].
So I'm returning {[2, 3], [4, 5]} to iteration 1
< Im BACK to the SECOND STAGE of ITERATION 1
got result from previous Clause 1 / Iteration 2, : {[2, 3], [4, 5]}
{left, right} = {[2, 3], [4, 5]}
Now I'm build the return value as {[head | left], right},
prepending 'head' (now is 1) to the previous value
of 'left' (now is [2, 3]) at each iteration,
'right' instead is always [4, 5].
And my final return is at least: {[1, 2, 3], [4, 5]}
{[1, 2, 3], [4, 5]}
In the schema, the beginning of every iteration is marked with
> FIRST STAGE of CLAUSE 1 / ITERATION n called as: ...
meanwhile the beginning of the continuation of the iteration is marked as
< I'm BACK to the SECOND STAGE of ITERATION n
Now we can clearly see that:
the first block is iterated three times;
the Clause 2 is called just ONE time;
second block is iterated three times, the first time it receive the result from the Clause 2, the remaining times from Clause 1;
the result of Clause 2 contains the right portion of the splitted list, computed in third iteration of Clause 1.
So, what is the role for Clause 2? It is a trick, a way to pass back, down to the continuation of the iterations, the otherwise inaccessible value of the right part of the splitted list.
Here it is a step-by-step explanation of the code:
In the first stage the value of the first parameter of the function, the variable I've called in_list, is decomposed in its head and tail components:
# FIRST STAGE
[head | tail] = in_list
then the head is pushed on the stack and the tail and the update counter are passed to the recursion:
result = split(tail, count - 1)
after count iterations, all the left-splitted elements are on the stack, and all the right-splitted elements are packed in the tail. The the Clause 2 is now called.
After the Clause 2 call, the recursion continue with the second stage, where the result variable is bound to the two (partially) splitted list returned by the previous split/2 iteration.
Now, at every iteration, we extract the left and right lists fron the result:
{left, right} = result
and add to the left the head popped from the stack ( that was computed in the first stage), returning the result to the caller:
return = {[head | left], right}
so at every iteration the left part grows 'till the final value.
The first result is returned by the Clause 2, matched when the iterations had reached the split point i.e. when count = 0. (Clause 2 will fire just one time). All the subsequent results will be returned by the folded second stages of the Clause 1 iterations.
This is the code to print the above schema:
def split(in_list, count), do: split(in_list, count, 1)
# Clause 1
def split(in_list=[head | tail], count, iteration) when count > 0 do
offset = String.duplicate " ", 5 * (iteration - 1)
IO.puts offset <> "> FIRST STAGE of CLAUSE 1 / ITERATION #{inspect iteration} called as: split( #{inspect in_list}, #{inspect(count)} ):"
IO.puts offset <> " Got 'head'=#{inspect head}, 'tail'=#{inspect tail}, 'count'=#{inspect count}"
if (count - 1) > 0 do
IO.puts offset <> " now I'm going to iterate passing the tail #{inspect(tail)},"
IO.puts offset <> " Clause 1 will match as the counter is still > 0"
else
IO.puts offset <> " Now the counter is 0 so I've reached the split point,"
IO.puts offset <> " and the Clause 2 instead of Clause 1 will match at the next iteration"
end
result = split(tail, count-1, iteration + 1)
IO.puts offset <> "< Im BACK to the SECOND STAGE of ITERATION #{inspect(iteration)}"
if (count - 1) == 0 do
IO.puts offset <> " got result from CLAUSE 2: #{inspect result}"
else
IO.puts offset <> " got result from previous Clause 1 / Iteration #{iteration + 1}, : #{inspect result}"
end
IO.puts offset <> " {left, right} = #{inspect result}"
{left, right} = result
IO.puts offset <> " Now I'm build the return value as {[head | left], right},"
IO.puts offset <> " prepending 'head' (now is #{inspect head}) to the previous value"
IO.puts offset <> " of 'left' (now is #{inspect left}) at each iteration,"
IO.puts offset <> " 'right' instead is always #{inspect right}."
return = {[head | left], right}
if (iteration > 1) do
IO.puts offset <> " So I'm returning #{inspect return} to iteration #{inspect(iteration - 1)}"
else
IO.puts offset <> " And my final return is at least: #{inspect return} "
end
return
end
# Clause 2
def split(list, _count, _iteration) do
IO.puts ""
IO.puts "> Greetings from CLAUSE 2 :-), got #{inspect(list)}, returning #{inspect({[], list})}"
IO.puts ""
{[], list}
end
Hope this can help to clarify a little bit the strategy adopted and the internal recursion mechanism.
(my English is not very good, hope someone can fix this text)
# the first element is head, the tail is the rest of the list
# count must be greater than 0 to match
def split([head | tail], count) when count > 0 do
# recursively call passing in tail and decrementing the count
# it will match a two element tuple
{left, right} = split(tail, count-1)
# return a two element tuple containing
# the head, concatenated with the left element
# and the right (i.e. the rest of the list)
{[head | left], right}
end
# this is for when count is <= 0
# return a two element tuple with an empty array the rest of the list
# do not recurse
def split(list, _count), do: {[], list}
I've added some comments to the code above.
The net effect is that the head of the list is continually stripped off and concatenated with the "left" list until count is decremented to 0. At that point you are have a two lists returned as a tuple.
The code is tricky, because it is not tail recursive, so it is not a loop and it remembers O(n) calls.
Lets try to analyze on a simple example where indent indicates level of recursion:
split([1,2,3], 2) ->
#head = 1, tail = [2,3], count = 2
{left, right} = split([2,3], 1) -> #this is the recursive call
#head = 2, tail = [3], count = 1
{left, right} = split([3], 0) #this call returns immediately, because it matches second clause
{left, right} = {[], [3]} #in this call
#what we have now is second list in place, we need to reassemble the first one from what we remember in recursive calls
#head still equals 2, left = [], right = [3]
{[head | left], right} = {[2], [3]} #this is what we return to higher call
#head = 1, left = [2], right = [3]
{[head | left], right} = {[1,2], [3]}
So the pattern is that you disassemble the list and remember its elements in recursion and then reassemble it. The simplest case for such pattern is:
def identity([]) -> []
def identity([head | tail]) do
# spot 1
new_tail = identity(tail)
# spot 2
[head | tail]
end
This function does nothing to the original list. It only traverses all elements. To understand the pattern, guess what happen when you place IO.puts head in spot 1 and spot 2.
Then try to modify it traverse only count of elements and then you will see how close you are to the split implementation.

Unique array of random numbers using functional programming

I'm trying to write some code in a functional paradigm for practice. There is one case I'm having some problems wrapping my head around. I am trying to create an array of 5 unique integers from 1, 100. I have been able to solve this without using functional programming:
let uniqueArray = [];
while (uniqueArray.length< 5) {
const newNumber = getRandom1to100();
if (uniqueArray.indexOf(newNumber) < 0) {
uniqueArray.push(newNumber)
}
}
I have access to lodash so I can use that. I was thinking along the lines of:
const uniqueArray = [
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100()
].map((currentVal, index, array) => {
return array.indexOf(currentVal) > -1 ? getRandom1to100 : currentVal;
});
But this obviously wouldn't work because it will always return true because the index is going to be in the array (with more work I could remove that defect) but more importantly it doesn't check for a second time that all values are unique. However, I'm not quite sure how to functionaly mimic a while loop.
Here's an example in OCaml, the key point is that you use accumulators and recursion.
let make () =
Random.self_init ();
let rec make_list prev current max accum =
let number = Random.int 100 in
if current = max then accum
else begin
if number <> prev
then (number + prev) :: make_list number (current + 1) max accum
else accum
end
in
make_list 0 0 5 [] |> Array.of_list
This won't guarantee that the array will be unique, since its only checking by the previous. You could fix that by hiding a hashtable in the closure between make and make_list and doing a constant time lookup.
Here is a stream-based Python approach.
Python's version of a lazy stream is a generator. They can be produced in various ways, including by something which looks like a function definition but uses the key word yield rather than return. For example:
import random
def randNums(a,b):
while True:
yield random.randint(a,b)
Normally generators are used in for-loops but this last generator has an infinite loop hence would hang if you try to iterate over it. Instead, you can use the built-in function next() to get the next item in the string. It is convenient to write a function which works something like Haskell's take:
def take(n,stream):
items = []
for i in range(n):
try:
items.append(next(stream))
except StopIteration:
return items
return items
In Python StopIteration is raised when a generator is exhausted. If this happens before n items, this code just returns however much has been generated, so perhaps I should call it takeAtMost. If you ditch the error-handling then it will crash if there are not enough items -- which maybe you want. In any event, this is used like:
>>> s = randNums(1,10)
>>> take(5,s)
[6, 6, 8, 7, 2]
of course, this allows for repeats.
To make things unique (and to do so in a functional way) we can write a function which takes a stream as input and returns a stream consisting of unique items as output:
def unique(stream):
def f(s):
items = set()
while True:
try:
x = next(s)
if not x in items:
items.add(x)
yield x
except StopIteration:
raise StopIteration
return f(stream)
this creates an stream in a closure that contains a set which can keep track of items that have been seen, only yielding items which are unique. Here I am passing on any StopIteration exception. If the underlying generator has no more elements then there are no more unique elements. I am not 100% sure if I need to explicitly pass on the exception -- (it might happen automatically) but it seems clean to do so.
Used like this:
>>> take(5,unique(randNums(1,10)))
[7, 2, 5, 1, 6]
take(10,unique(randNums(1,10))) will yield a random permutation of 1-10. take(11,unique(randNums(1,10))) will never terminate.
This is a very good question. It's actually quite common. It's even sometimes asked as an interview question.
Here's my solution to generating 5 integers from 0 to 100.
let rec take lst n =
if n = 0 then []
else
match lst with
| [] -> []
| x :: xs -> x :: take xs (n-1)
let shuffle d =
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
let rec range a b =
if a >= b then []
else a :: range (a+1) b;;
let _ =
print_endline
(String.concat "\t" ("5 random integers:" :: List.map string_of_int (take (shuffle (range 0 101)) 5)))
How's this:
const addUnique = (ar) => {
const el = getRandom1to100();
return ar.includes(el) ? ar : ar.concat([el])
}
const uniqueArray = (numberOfElements, baseArray) => {
if (numberOfElements < baseArray.length) throw 'invalid input'
return baseArray.length === numberOfElements ? baseArray : uniqueArray(numberOfElements, addUnique(baseArray))
}
const myArray = uniqueArray(5, [])

Standard ML: Size of binary tree computed incorrectly?

My book has the following function which calculates the number of non-leaf nodes in a binary tree:
fun size Empty = 0
| size(Node(t_1, _, t_2)) = size t_1 + size t_2 + 1;
Suppose I want to calculate all nodes in a binary tree. How would I modify this function to do so?
Here's what I was thinking:
fun size Empty = 0
| size(Node(Empty, _, Empty)) = 1
| size(Node(t_1, _, t_2)) = size t_1 + size t_2 + 1;
Does this look right?
Thanks,
bclayman
Both of the implementations that you provided are actually the same. The second case of your second implementation is a special case of you your third pattern. For your first implementation, size(Node(Empty,1,Empty)) will recurse one the left subtree, returning 0, recurse on the right subtree, which returns 0, and then adds 1, yielding the result 1. In fact, if you switch the order of the second and third case, the compiler will tell you that it is redundant:
test.sml:3.5-5.38 Error: match redundant
Empty => ...
Node (t_1,_,t_2) => ...
--> Node (Empty,_,Empty) => ...
Matt is correct that your two functions are functionally the same -- both of which return a count of all nodes in the tree. I didn't notice this at first since I took it at face value that your first function counted nonleaf nodes and then noticed that your Node(Empty,_,Empty) pattern is the correct pattern of a leaf (if a leaf is defined as a node with no non-empty children). But -- this means that the function in the book doesn't just count nonleaf (parents) nodes. If you do want a function which just counts parent nodes, there is a use for your pattern after all:
fun parents Empty = 0
| parents(Node(Empty, _, Empty)) = 0
| parents(Node(t_1, _, t_2)) = parents t_1 + parents t_2 + 1;
If your application of trees is one in which heavy use is made of the parent node vs. leaf node distinction, you could (at the cost of making some of your function definitions more involved) ditch the Node constructor in favor of separate Parent and Leaf constructors. Something like:
datatype 'a tree = Empty | Leaf of 'a | Parent of 'a tree * 'a * 'a tree;
Then you can write functions like
fun countLeaves Empty = 0
| countLeaves (Leaf _) = 1
| countLeaves (Parent(t1,_,t2)) = countLeaves t1 + countLeaves t2;
So e.g.
- val t = Parent(Parent(Leaf "2", "*", Leaf "3"), "+", Leaf "4");
- countLeaves t;
val it = 3 : int

Tail recursion in SML does not present any output

Following my previous post here , I tried to do what was suggested and convert the code
into a Tail-recursion method with let .
The original code - which does not work (due to using val inside if condition) :
fun func() =
val decimal = 0 (* the final result *)
val multiple = 0 (* keeps track of multiples, eg. In XXV, X would be a multiple *)
val current = 0 (* the digit currently being processed *)
val top = 0 (* value of the last element in the list *)
val last_add = 0 (* the last digit that wasn't a multiple, or subtraction operation *)
val last_sub = 0
val problem = 0 (* if value is 1 then there is a problem with the input *)
val myList = [1,2,3,4,5] (* the list has more values *)
while (myList <> []) (* run while the list is not empty *)
val current = tl(myList) (* grab the last element from the list *)
val myList = tl(myList) (* remove the last element from the list *)
val top = tl(myList) (* grab the value at the end of the list *)
if ( myList <> []) andalso (current > top))
then
val decimal = decimal + current - top
val last_sub = top;
val myList = tl(myList)
else
if ( (myList = []) andalso (current = top))
then val decimal = decimal + current
val multiple = multiple + 1
else
if (last_sub = current)
then val problem = 1
else
val decimal = decimal + current
val multiple = 0
val last_add = current
And the code as a tail-recursion method :
fun calc [] = 0
|calc [x] = x
|calc (head::tail) =
let
val decimal = 0
val multiple = 0
val current = 0
val top = 0
val last_add = 0
val last_sub = 0
val problem = 0
val doNothing = 0
in
let
val current = hd(rev(head::tail)) (* grab the last element *)
val head::tail = rev(tl(rev(head::tail))) (* POP action - remove the last element from the list *)
val top = hd(rev(head::tail)) (* grab the new last element after removing *)
in
if (current > top) then
let
val decimal = decimal + current - top
val last_sub = top
val head::tail = rev(tl(rev(head::tail))) (* POP action - remove the last element from the list *)
in
calc(head::tail)
end
else
if ( (head::tail = []) andalso (current = top))
then let
val decimal = decimal + current
val multiple = multiple + 1
in
calc(head::tail)
end
else
if (last_sub <> current)
then let
val decimal = decimal + current
val multiple = 0
val last_add = current
in
calc(head::tail)
end
else
(* do nothing *)
val doNothing = 0
end
end;
However , when I try to enter :
calc([0,100,20,30,4,50]);
I get :
uncaught exception Bind [nonexhaustive binding failure]
raised at: stdIn:216.13-216.50
I know the code is very hard to read and pretty long , but it would be greatly appreciated
if someone could explain to me how to fix it , or help me find the reason for this output .
Thanks
You have a few issues with your code.
First of all, you can use last to grab the last element of a list. See the List documentation for more info. But unless you have a really good reason to do so, it's easier and much more efficient to simply start from the beginning of the list and pop elements off the beginning as you recurse. You already have the first element bound to head in your code using pattern matching.
Secondly, unless you use refs (which you probably don't want to do) there are no variables in Standard ML, only values. What this means is that if you want to carry state between invocations, any accumulators need to be parameters of your function. Using a helper function to initialize accumulators is a common pattern.
Third, instead of comparing a list to [] to test if it's empty, use the null function. Trust me on this. You'll get warnings using = because of subtle type inference issues. Better yet, use a pattern match on your function's parameters or use a case statement. Pattern matching allows the compiler to tell you whether you've handled all possible cases.
Fourth, SML typically uses camelCase, not snake_case, for variable names. This is more stylistic, but as you write more code and collaborate, you're going to want to fit with the conventions.
Fifth, when you do recursion on a list, don't try to look at multiple values in the list. This complicates things. Treat it as a head element and tail list, and everything will become much simpler. In my code, instead of keeping current in the list, I did this by splitting it out into a separate parameter. Have a base case where you simply return the answer from one of your accumulators, and a recursive case where you recurse with updated accumulator values and a single value popped from your list. This eliminates the problem scenario.
I'm not sure if this logic is correct since I don't know what you're trying to calculate, but check out this code which illustrates some of the things I talked about.
(* This is the helper function which takes accumulators as
parameters. You shouldn't call this directly. *)
fun calc' decimal _ _ _ _ [] =
(* We processed everything in the list. Just return the accumulator. *)
decimal
| calc' decimal multiple lastAdd lastSub current (top::tail) =
(* This case is for when there are 1 or more elements in the list. *)
if current > top then
calc' (decimal + current - top) multiple lastAdd top top tail
else if current = top then
calc' (decimal + current) (multiple + 1) lastAdd lastSub top tail
else
calc' (decimal + current) 0 current lastSub top tail
(* This is the function you should call. *)
fun calc [] = 0
| calc [_] = 0 (* Given a single-element list. *)
| calc (x::xs) =
(* Apply the helper with correct initial values. *)
calc' 0 0 0 0 x xs
In a functional language, instead of assigning to a variable when you want to change it, simply recurse and specify the new value for the correct parameter. This is how you write a "loop" in a functional language using recursion. As long as you only use tail-recursion, it will be just as efficient as a while loop in your favorite imperative language.

Resources