Tail Recursion

Tail Recursion

 

Interviewer task: get the interviewee to write factorial tail-recursively

 

Interviewer says: use recursion to implement factorial : 

Interviewee nearly jumps with glee: 

 

 

function factorial (n){
    return n ? n * factorial(n - 1) : 1
}

Tail Recursion

 

Interviewer: What's the problem with this implementation? (Give interviewee time to respond). 

 

Interviewer: This function calls itself n times and therefore needs n stack frames. JavaScript has a limit on the stack size. 

factorial(10000) -->

RangeError: maximum call stack size exceeded

 

 

 

 

Text

fact(4)
#=> 4 * fact(3)
#=> 4 * ( 3 * fact(2) )
#=> 4 * ( 3 * ( 2 * fact(1) ) )
#=> 4 * ( 3 * ( 2 * 1 ) )
#=> 4 * ( 3 * 2 )
#=> 4 * 6
#=> 24

Tail Recursion

 

This implementation of factorial invokes * last, not factorial

 

 

 

 

Which is why we need n stack frames 

factorial(n){
    return n ? n * factorial(n - 1) : 1
}

Tail Recursion

 

Tail-Recursion --> there is nothing to do after the function returns except return its value

 

A compiler implements tail call optimization if, when it recognizes a tail-recursive function, it turns the recursive call into a while loop, thereby reusing the current stack frame 

 

no more worrying about space inefficiency 

 

 

 

 

 

Tail Recursion

Interviewer: Now re-write factorial in a recursive manner that enables the compiler to convert this function into a loop. 

This means that the last function invoked must be the recursive function 

Tail Recursion 

Tail-Call Optimization: when a  function returns the result of calling itself, the language doesn't perform another function call, it turns the performs the function invocation with a while loop 

Tail Recursion

Write factorial so that the last function invoked is the recursive function.

Solution: 

 

function factorial(n) {
    function recur(n, acc) {
        if (n == 0) {
            return acc;
        } else {
            return recur(n-1, n*acc);
        }
    }
    return recur(n, 1);
}

Tail Recursion

Tail-Recursive Factorial Stack Frame

factorial(5) → recur(5,1)
recur(5,1) → recur(4,5)
recur(4,5) → recur(3,20)
recur(3,20) → recur(2,60)
recur(2,60) → recur(1,120)
recur(1,120) → recur(0,120)
recur(0,120) → 120

Tail Recursion

 

Trampoline 

1 - a loop that iteratively invokes thunk-returning functions

2 - a tool used to implement tail-recursive function calls in stack-oriented programming languages 

function trampoline(f) {
    while (f && f instanceof Function) {
        f = f.apply(f.context, f.args);
    }
    return f;
}

Tail Recursion

By ayana28

Tail Recursion

  • 1,815