I think you have the right idea.
I don’t think you need all this complexity. Imagine JavaScript was
if (veryExpensiveFunction()) { doThis(); } else { doThat(); }
Now imagine that a veryExpensiveFunction implemented.
function veryExpensiveFunction() { return true || evenMoreExpensiveFunction(); }
If JavaScript, because || lazy (only evaluates the second argument, if necessary), it will return very quickly (because true is, well, true!). If it were implemented instead
function veryExpensiveFunction() { var a = true; var b = evenMoreExpensiveFunction();
This will take some time to evaluate, because you overestimated the arguments. Now imagine the magic applied to || has been applied to every function (i.e. lazy language), and you can probably imagine what performance benefits laziness can bring.
In your example
function tak(x,y,z){ return (x <= y) ? y : tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y)); }
Imagine that everything was lazy.
var a = tak(1,2,3);
It does nothing (nothing needs to be evaluated). a not used, so nothing is evaluated.
var a = tak(1,2,3); console.log(a);
Now we can manage the tak score. Estimating how we need to get the results, we first substitute the values in (we replace the variables with our arguments). Then we calculate the condition, and then only that side of the conditional that we need.
console.log((1 <= 2) ? 2 : tak(tak(1-1, 2, 3), tak(2-1, 1, 3), tak(3-1, 1, 2)); console.log( true ? 2 : tak(tak(1-1, 2, 3), tak(2-1, 1, 3), tak(3-1, 1, 2)); console.log(2);
In this example (assuming that I did not make any terrible typos), we do not need to evaluate anything other than arguments, and no recursive calls are made.