The code samples are taken from
Last active
December 10, 2017 15:47
-
-
Save saip106/bc4a4c3bb2e2a25723ec to your computer and use it in GitHub Desktop.
Trampoline & Tail Call Optimization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is a naive way to find if a number is even | |
The purpose is to show that recursive calls result in Maximum call stack size exceeded error | |
*/ | |
function isEven(n) { | |
if(n === 1) { | |
return false; | |
} | |
if (n ===2) { | |
return true; | |
} | |
return isEven(n - 2); //recursion | |
} | |
var x = 99999; //some large number | |
console.log(x + ' is even: ' + isEven(x)); | |
//Results in the following error: | |
//Uncaught RangeError: Maximum call stack size exceeded |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is slightly better over the previous version | |
It wraps recursion call in a function | |
But it leaves it up to the user to call the function multiple times | |
This will work for large numbers but is not practical | |
*/ | |
function isEven(n) { | |
if(n === 1) { | |
return false; | |
} | |
if (n ===2) { | |
return true; | |
} | |
//instead of recursively calling this function we wrap it in a function | |
return function () { | |
return isEven(n - 2); | |
} | |
} | |
var x = 9; | |
console.log(x + ' is even: ' + isEven(x)()()()()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Here we use trampoline function to convert recurion to a loop | |
This works (even for large numbers) but has two issues | |
a. for every function we need to create a corresponding trampoline | |
b. Out isEven function looks odd returning a function | |
*/ | |
function trampoline(f, n) { | |
var value = f(n); | |
while (typeof value === 'function') { | |
value = value(); | |
} | |
return value; | |
} | |
function isEven(n) { | |
if(n === 1) { | |
return false; | |
} | |
if (n ===2) { | |
return true; | |
} | |
//instead of recursively calling this function we wrap it in a function | |
return function () { | |
return isEven(n - 2); | |
} | |
} | |
var x = 99999; | |
console.log(x + ' is even: ' + tranpoline(isEven, x)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Here we fix the first issue listed in above version | |
*/ | |
function trampoline(f) { | |
var value = f(Array.prototype.slice.call(arguments, 1)); | |
while (typeof value === 'function') { | |
value = value(); | |
} | |
return value; | |
} | |
function isEven(n) { | |
if(n === 1) { | |
return false; | |
} | |
if (n ===2) { | |
return true; | |
} | |
//instead of recursively calling this function we wrap it in a function | |
return function () { | |
return isEven(n - 2); | |
} | |
} | |
var x = 99999; | |
console.log(x + ' is even: ' + tranpoline(isEven, x)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
The implementation for tail-call-optimization function is taken from https://gist.github.com/Gozala/1697037 | |
*/ | |
function tco(f) { | |
var value, isActive = false, accumulated = []; | |
return function accumulator() { | |
accumulated.push(arguments); | |
if(!isActive) { | |
isActive = true; | |
while(accumulated.length) { | |
value = f.apply(this, accumulated.shift()); | |
} | |
isActive = false; | |
} | |
return value; | |
}; | |
}; | |
var isEven = tco(function (n) { | |
if(n === 1) { | |
return false; | |
} | |
if (n ===2) { | |
return true; | |
} | |
return isEven(n - 2); | |
}); | |
var x = 999999; | |
console.log(x + ' is even: ' + isEven(x)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment