Today I learned that tail recursion optimization can really solve the classic problem of stack overflow in recursive functions that depend on data size
this I saw by writing a simple sum function in Scala that sums up a list
val x = (1 to 3).toList
// simple recursive function
def sum(x: List[Int]): Int = {
if (x.isEmpty) 0
else x.head + sum(x.tail)
}
ok so far so good, this works, and return 6 for the simple list of size 3.
But change the 3 to 300000 and you will see a stackOverFlow in the Scala workspace (you save the workspace and Scala will re compute). This is because a new frame is added to the stack for each recursive call and soon that exceeds the stack limit.
How do you solve this?
Tail recursion comes to the rescue. The term applies to functions whose last call is actually a self call, without any other computations. Scala compiler will internally then convert such functions into a while loop with goto, instead of pure recursion, hence avoiding the stack overflow issue
you can see this in action if you change the method to
def sumX(x: List[Int], seed: Int): Int = {
if (x.isEmpty) seed
else sumX(x.tail, seed + x.head)
}
Now you can call
sumX(x, 0) and this will work no matter how large the list is. The initial seed value should be 0 of course.
But this is an odd looking api, so let's fix it up by wrapping up this into an internal function so we don't have to provide the initial seed
def sum(x: List[Int]): Int = {
def sumX(x: List[Int], seed: Int): Int = {
if (x.isEmpty) seed
else sumX(x.tail, seed + x.head)
}
sumX(x, 0)
}
Much better, now call sum(x) and you will get what you want.
Happy Scala coding! I love this language
Comments
Post a Comment