Tail recursive functions in Scheme

Eogcloud picture Eogcloud · Dec 2, 2012 · Viewed 14.1k times · Source

I'm studying for a Christmas test and doing some sample exam questions, I've come across this one that has me a bit stumped

Question

I can do regular recursion fine, but I can't wrap my head around how to write the same thing using tail recursion.

Regular version:

    (define (factorial X)
      (cond
            ((eqv? X 1) 1)
            ((number? X)(* X (factorial (- X 1))))))

Answer

Óscar López picture Óscar López · Dec 2, 2012

For a function to be tail recursive, there must be nothing to do after the function returns except return its value. That is, the last thing that happens in the recursive step is the call to the function itself. This is generally achieved by using an accumulator parameter for keeping track of the answer:

(define (factorial x acc)
  (if (zero? x)
      acc
      (factorial (sub1 x) (* x acc))))

The above procedure will be initially called with 1 as accumulator, like this:

(factorial 10 1)
=> 3628800

Notice that the accumulated value gets returned when the base case is reached, and that the acc parameter gets updated at each point in the recursive call. I had to add one extra parameter to the procedure, but this can be avoided by defining an inner procedure or a named let, for example:

(define (factorial x)
  (let loop ((x x)
             (acc 1))
    (if (zero? x)
        acc
        (loop (sub1 x) (* x acc)))))