Skip to content

Instantly share code, notes, and snippets.

@jneen
Created June 23, 2012 04:21
Show Gist options
  • Save jneen/2976833 to your computer and use it in GitHub Desktop.
Save jneen/2976833 to your computer and use it in GitHub Desktop.
var P = require('pjs').P;
var util = require('util');
var stack = function() {
return (new Error).stack.split(/\s+at\s+/).slice(1);
}
var slice = [].slice;
var Thunk = P(function(thunk) {
thunk.toString = function() {
return '[Thunk '+util.inspect(this.fn)+' '+util.inspect(this.args)+']';
}
thunk.init = function(fn, args) {
this.fn = fn;
this.args = slice.call(args);
};
thunk.call = function() {
return this.fn.apply(null, this.args);
}
thunk.trampoline = function() {
var thunk = this;
for (;;) {
console.log('bounce', thunk);
if (thunk instanceof Thunk) {
thunk = thunk.call();
}
else {
return thunk;
}
}
}
});
function id(x) { return x; }
function makeTrampoline(def) {
function recurse() { return Thunk(thunkfn, arguments); }
var thunkfn = def(recurse);
return function() {
var args = slice.call(arguments);
return Thunk(thunkfn, [id].concat(args)).trampoline();
}
}
var gcd = exports.gcd = makeTrampoline(function(recurse) {
return function(cc, a, b) {
// prevent infinite loop on NaN
if (isNaN(a) || isNaN(b)) return cc(NaN);
if (a === 0 || b === 0) return cc(1.0/0);
// ensure a < b
if (a > b) {
var tmp = a;
a = b; b = tmp;
}
var mod = b % a;
// if a divides b, the gcd is a
if (mod === 0) return cc(a);
// otherwise recurse with Euclid's algorithm
return recurse(cc, mod, a);
}
});
var factorial = exports.factorial = makeTrampoline(function(recurse) {
function multiplier(cc, n) {
return function(m) { return cc(m * n); };
}
return function(cc, n) {
if (n <= 1) return cc(1);
return recurse(multiplier(cc, n), n - 1);
};
});
console.log(factorial(6));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment