Reputation: 4122
I'm new to scala. To practice recursion I set myself the task of finding the max value of an array. My base case is an array of length 1. For each recursive pass I'm comparing the sizes of the array values 0 and 1, eliminating the smaller value until the base case is met.
def max(m: Array[Int]): Int = {
if (m.length == 1) m(0)
else if (m(0) > m(1)) m.take(1)
else m.take(0)
return max(m)
}
However in the repl this returns nothing (presumably an infinite loop). I don't understand why the array doesn't reduce to length 1. Do I need a secondary inner function or something?
Upvotes: 1
Views: 999
Reputation: 88378
This is definitely an infinite loop, as you are recursively calling max
with the same argument you passed in (in the lingo, take
is not a modifier).
To answer the rest of the question, you do not need an inner helper function.
Try to translate the following algorithm to Scala:
m.take(1)
, call this max_of_rest
m(0)
and max_of_rest
Have fun learning recursion in Scala!
ADDENDUM
The above algorithm, while it produces the correct answer, does so inefficiently. Consider:
maximum([2, 4, 1, 10, 3])
= max(2, maximum([4, 1, 10, 3]))
= max(2, max(4, maximum([1, 10, 3])))
= max(2, max(4, max(1, maximum([10, 3]))))
= max(2, max(4, max(1, max(10, maximum([3])))))
= max(2, max(4, max(1, max(10, 3))))
= max(2, max(4, max(1, 10)))
= max(2, max(4, 10))
= max(2, 10)
= 10
Note how each of calls "pile up" on the call stack, consuming lots of extra memory. It is much better in this case to use a tail-recursive formulation.
maximum([2, 4, 1, 10, 3])
= _maximum([4, 1, 10, 3], max(4, 2))
= _maximum([1, 10, 3], max(1, 4))
= _maximum([10, 3], max(10, 4))
= _maximum([3], max(3, 10))
= _maximum([], 10)
= 10
Now in this tail-recursive case, as pointed out by Joost den Boer, you do have a second function. You can see that this inner recursive function works like this
_maximum(a, v) =
if a is empty return v
else return _maximum(a.take(1), max(a(0), v))
The outer function goes something like
maximum(a) =
if a is empty raise an error
else return _maximum(a.take(1), a(0))
I'm purposely not using Scala syntax so you can enjoy working it out. Have fun!
Upvotes: 4
Reputation: 2035
m.take()
does not modify m
. As a result you are calling max(m)
with the very same array as an argument over and over.
scala> val m = Array(1, 2, 3, 4, 5);
m: Array[Int] = Array(1, 2, 3, 4, 5)
scala> m.take(1)
res0: Array[Int] = Array(1)
scala> m
res1: Array[Int] = Array(1, 2, 3, 4, 5)
Also notice that take()
does not do at all what you think it is doing.
scala> m.take(0)
res2: Array[Int] = Array()
scala> m.take(3)
res3: Array[Int] = Array(1, 2, 3)
Upvotes: 2