So, Lua optimizes tail recursion calls.
At first glance, this is no big deal. Very few recursive functions are tail recursive, that is, have the recursive call as the very last thing in the function, at first glance.
Consider the recursive factorial, for a real easy example.
function fact_1(num) if num <= 1 then return 1 else return num * fact_1 (num - 1) end end
While it looks like the recursive call is the last thing in the function, it really isn’t. The multiplication of num and the result of the result of the recursive call is the last thing done in the function, so this isn’t tail recursion.
But it can be “easily” turned into a function that is tail recursive. I quote “easily” since the first two or three or ten times you see the “easy” translation, you may not believe it, or at least may not believe it’s really easier. (I had students who figured it out the first time and others who took a lot more tries. A lot more.)
What you have to do is carry the result with you down into the recursion. You’ll update the solution as you go, so that when you finally get to the base case, you’ll have the result ready to return. As the last step of the function. Thus, tail recursion. Code to do this is:
function fact_2 (num, result) if num <= 1 then return result else return fact_2 (num - 1, result * num) end end
The only thing left to do is to rewrite the main factorial function to use this tail recursive version:
function factorial (num) return fact_2(num, 1) end
Does it really matter? Does Lua really optimize tail recursion?
I tried the following non-tail recursive code and could compute up to 19,997 before getting a stack overflow error.
function sum_badly(max) if max <= 1 then return max end local other_sum = sum_badly(max - 1) return other_sum + max end
And sure enough, the tail recursive version below allowed me to go to at least 100,000,000, so I’m convinced Lua does optimize tail recursion.
function sum_well_helper(max, current) if max < 1 then return current else return sum_well_helper(max -1, current + max) end end function sum_well(max) return sum_well_helper(max, 0) end
The code is in my GitHub account if you want to see for yourself. The solutions to the Day 1 problems are also there.
That’s enough of Day 1 for now. Onto to tables.
Leave a Reply