Search code examples
recursionschemelisptail-recursion

Tail recursive functions in Scheme


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))))))

Solution

  • 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)))))