Skip to content

Instantly share code, notes, and snippets.

@raganwald
Last active August 29, 2015 14:02
Show Gist options
  • Select an option

  • Save raganwald/bf56b0f004a75ca78031 to your computer and use it in GitHub Desktop.

Select an option

Save raganwald/bf56b0f004a75ca78031 to your computer and use it in GitHub Desktop.
Faking Predicate Dispatch in JavaScript
function nameAndLength(name, length, body) {
var abcs = [ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
'z', 'x', 'c', 'v', 'b', 'n', 'm' ],
pars = abcs.slice(0, length),
src = "(function " + name + " (" + pars.join(',') + ") { return body.apply(this, arguments); })";
return eval(src);
}
function imitate(exemplar, body) {
return nameAndLength(exemplar.name, exemplar.length, body);
}
function guard (guardFn, optionalFn) {
function guarded (fn) {
return imitate(fn, function () {
if (guardFn.apply(this, arguments))
return fn.apply(this, arguments);
});
}
return optionalFn == null
? guarded
: guarded(optionalFn);
}
function getWith (prop, obj) {
function gets (obj) {
return obj[prop];
}
return obj === undefined
? gets
: gets(obj);
}
function mapWith (fn, mappable) {
function maps (collection) {
return collection.map(fn);
}
return mappable === undefined
? maps
: maps(collection);
}
function pluckWith (prop, collection) {
var plucker = mapWith(getWith(prop));
return collection === undefined
? plucker
: plucker(collection);
}
function Match () {
var fns = [].slice.call(arguments, 0),
lengths = pluckWith('length', fns),
length = Math.min.apply(null, lengths),
names = pluckWith('name', fns).filter(function (name) { return name !== ''; }),
name = names.length === 0
? ''
: names[0];
return nameAndLength(name, length, function () {
var i,
value;
for (i in fns) {
value = fns[i].apply(this, arguments);
if (value !== undefined) return value;
}
});
}
function equals (x) {
return function eq (y) { return (x === y); }
}
function not (fn) {
var name = fn.name === ''
? "not"
: "not_" + fn.name;
return nameAndLength(name, fn.length, function () {
return !fn.apply(this, arguments)
});
}
var worstPossibleTestForEven = Match(
guard(equals(0), function (n) { return true; }),
guard(equals(1), function (n) { return false; }),
function (n) { return worstPossibleTestForOdd(n - 1)}
)
var worstPossibleTestForOdd = Match(
guard(equals(0), function (n) { return false; }),
guard(equals(1), function (n) { return true; }),
function (n) { return worstPossibleTestForEven(n - 1)}
)
worstPossibleTestForEven(6)
//=> true
worstPossibleTestForOdd(42)
//=> false
@raganwald
Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment