So, that difference in the rewriting rules actually translates directly to a

difference in the execution, in the actual, execution on a computer.

In fact, it turns out that if you have a recursive function that calls itself as

its last action, then you can reuse the stack frame of that function.

This is called tail recursion. And by applying that trick, it means that

a tail recursive function can execute in constant stuck space, so it's really just

another formulation of an iterative process.

Could say a tail recursive function is the functional form of a loop, and it executes

just as efficiently as a loop. So if we go back to GCD, we see that in

the else part, GCD calls itself as its last action.

And that translate its, to a rewriting sequence that was essentially constant

size, and that will, in the actual execution on a computer, translate into a

tail recursive call that can execute in constant space.

On the other hand, if you look at factorial again, then you'll see that

after the call to factorial n minus one, there was still work to be done, namely,

we had to multiply the result of that call with the number N.

So that call here is not a tail recursive call, and it becomes evident in the

reduction sequence, where you see that actually there's a buildup of intermediate

results that we all have to keep until we can compute the final value.

So that factorial would not be a tail recursive function.

Both factorial and GCD only call itself

but in general, of course, a function could call other functions.

So the generalization of tail recursion is that, if the last action of a

function consists of calling another function, maybe the same, maybe some other

function. The stack frame could be reused for both

functions. Such calls are called tail calls.

After having gone through the exercise, you might ask yourself, should every

function be tail recursive? Well, not really.

The interest of tail recursion is mostly to avoid very deep recursive chains.

Most implementations of, the JBM, for instance, limit the maximal depth of

recursion to a couple of thousand stack frames.

So if your, the input data is such that these deep recursive chains could happen,

then yes it's a good idea to reformulate your function to be tail recursive, to run

in constant stack frame, so as to avoid stack overflow exceptions.

On the other hand, if your input data are not,

susceptible to deep precausive chains then

clarity trumps efficiency evert time, so write your function the clearest way you

can. Which often is not terricosive.

And don't worry about the steck frames that are spent.

As Donald Knuth has said, premature optimization is the source of all evil.

And that's the model that's very valuable to follow.