I have a question regarding this article.
Between this code
function odds(n, p) {
if(n == 0) {
return 1
} else {
return (n / p) * odds(n - 1, p - 1)
}
}
and this code
(function(){
var odds1 = function(n, p, acc) {
if(n == 0) {
return acc
} else {
return odds1(n - 1, p - 1, (n / p) * acc)
}
}
odds = function(n, p) {
return odds1(n, p, 1)
}
})()
1) I'm confused about how much this helps. Does the second snippet simply have a tail call that creates less overhead because it calculates what it needs before it calls itself again, or is there something more I'm missing?
As I understand it, the tail call still isn't eliminated, just optimized.
2) And why does there need to be odds
and odds1
anyway? It still isn't clear to me either.
I'm confused about how much this helps. Does the second snippet simply have a tail call that creates less overhead because it calculates what it needs before it calls itself again, or is there something more I'm missing?
As I understand it, the tail call still isn't eliminated, just optimized.
If the end of a procedure looks like this:
push args
call foo
return
Then the compiler can optimize that away to just
jump startOfFoo
Eliminating the procedure call entirely.
And why does there need to be odds and odds1 anyway? It still isn't clear to me either.
The "contract" of odds
specifies only two arguments - the third argument is just an implementation detail. So you hide that away in an internal method, and present a "wrapper" as the external API.
You could call odds1
something like oddsImpl
and it would make it clearer, I think.