CS 201: Tail Recursion

Defining local variables with let and let*

let creates local variables within your procedure. It does not pollute the global namespace. Below we create two local variables, y and z.

let* is like let, but you can refer to other local variables within let*.

This is what you would need to do if you did not have let*.

Defining Functions with Optional Arguments

Below we define a function size which returns the size of an object. By default, it uses length as the measure of size, but you can specify another function to specify the size. Note the dot notation to specify the optional argument proc

The problem is that max unlike length takes a variable number of arguments, not a single list.

We can use square brackets to specify the default value for an optional argument: [optional-arg default-value]

Recursive Integer Operations

We define the following functions:

Note that both split and join used an auxiliary function to implement the recursion. We can write join without a helper function by using a default parameter for the initial result.

More Recursion: append and replicate

append splices together two lists. Note that cons is slightly different. We can define my-append using recursion.

We define replicate which creates n copies of an object in a list.

Tail Recursion

Both my-append and replicate are recursive. We note that both have to wait for the return of the recursive call before returning a final value. Since recursion is normally implemented by pushing recursive calls onto a memory stack, these recursive calls can consume lots of resources.

Guy Steele and Gerry Sussman of MIT in the 1970's noted that there is a way to avoid the overhead of the recursive calls piling up on the stack using tail recursion. The idea is simple and elegant. You write the procedure so that the last call in the function is the recursive call. That way, there is no need to wait around for the result.

The nested calls to replicate indicate the number of items sitting on the stack.

We can define a tail recursive version of replicate for comparison

We need to trace the helper function trrepaux

Each call to trrepaux is independent. They do not have to leave calls on the stack.

We can redefine trreplicate using the optional parameter and avoid the helper function.

We can create tail recursive versions of familiar functions such as

both with and without helper functions.

In racket, -inf.0 is negative infinity as a real.

Even more power.

There is a faster algorithm for exponentiation. See page 48 of The Algorithm Design Manual by Skienna. pdf

It is faster than expt

Exercise: Rewrite the my-append function as a tail-recursive function.

Ackermann Function

See (https://en.wikipedia.org/wiki/Ackermann_function)

Ackermann was an interesting guy. He gave up his career for love, or at least marriage. Guy Steele had a similar shadow on his career.

Now we will memoize ack to avoid repetitive computations.