Reputation: 103
So one of the common examples of tail recursion I see is:
function factorial(x) {
if (x <= 0) {
return 1;
} else {
return x * factorial(x-1); // (A)
}
}
An it's optimized for Tail call with:
function factorial(n) {
return facRec(n, 1);
}
function facRec(x, acc) {
if (x <= 1) {
return acc;
} else {
return facRec(x-1, x*acc); // (A)
}
}
I get this. But my question is: Why isn't the *
in this case a function that could be optimized on?
Couldn't I rewrite the top as
function factorial(x) {
if (x <= 0) {
return 1;
} else {
return multiply(x, factorial(x-1)); // (A)
}
}
I know this won't work. I think it's just because it's not a true tail recursive call? Would this still be tail optimized though?
Upvotes: 0
Views: 63
Reputation: 1074148
Your last example isn't a tail call because you have to keep calling factorial
before you can call multiply
. Consider:
factorial(5) can't call multiply until it has the result from factorial(4) can't call multiply until it has the result from factorial(3) can't call multiply until it has the result from factorial(2) can't call multiply until it has the result from factorial(1) can't call multiply until it has the result from factorial(0)
it's only at this point that you stop recursing and call multiply
. So, no tail call.
It's probably also worth noting that TCO is pretty much only implemented by Safari's JavaScriptCore. it isn't implemented by Chrome's V8 or Firefox's SpiderMonkey, nor is it likely to be, spec or no spec. :-) More here and here.
I should note that in your title you ask
Why does '+' not allow that?
It does. TCO doesn't care what the operation is — *
vs +
— just that it be in the tail position.
Upvotes: 7