-
-
Save CrossEye/5307355 to your computer and use it in GitHub Desktop.
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
// clean and pure: | |
function cons(x, y) { | |
return function(pick) { | |
return pick(x, y); | |
} | |
} | |
// does more stuff: | |
function cons(x, y) { | |
var fn = function(pick) { | |
return pick(x, y); | |
}; | |
fn.toString =function() { | |
if (isEmpty(this)) {return "()";} | |
var h = car(this), t = cdr(this), nested = arguments.length > 0; | |
return (nested ? "" : "(") + (pair(h) ? h.toString() : h) + (isEmpty(t) ? "" : " " + t.toString(nested)) + (nested ? "" : ")"); | |
}; | |
fn.pair = true; // to support atom? function | |
return fn; | |
} | |
function car(fn) { | |
return fn(function(x, y) { return x; }); | |
} | |
function cdr(fn) { | |
return fn(function(x, y) { return y; }); | |
} | |
function atom(x) { | |
return (x !== null) && (x !== undefined) && !x.pair; | |
} | |
function pair(x) { | |
return x && x.pair; | |
} | |
function isEmpty(lat) { | |
return lat == null || car(lat) == null; | |
} | |
function list() { | |
var args = [].slice.call(arguments); | |
return (args.length === 0) ? null : cons(args.shift(), list.apply(null, args)); | |
} | |
function map(fn, lat) { | |
return (lat === null) ? null : cons(fn(car(lat)), map(fn, cdr(lat))); | |
} | |
function foldl(fn, acc, lat) { | |
return (lat === null) ? acc : foldl(fn, fn(acc, car(lat)), cdr(lat)); | |
} | |
function foldr(fn, acc, lat) { | |
return (lat === null) ? acc : fn(car(lat), foldr(fn, acc, cdr(lat))); | |
} | |
function filter(pred, lat) { | |
return (lat === null) ? null : (pred(car(lat))) ? cons(car(lat), filter(pred, cdr(lat))) : filter(pred, cdr(lat)); | |
} | |
function append(l, m) { | |
return (l === null) ? m : cons(car(l), append(cdr(l), m)); | |
} | |
function reverse(l) { | |
return (l === null) ? null : append(reverse(cdr(l)), cons(car(l), null)); | |
} | |
function not(fn) {return function() {return !fn.apply(this, arguments);};} // or one arg only? | |
function any(pred, lat) { | |
return (lat === null) ? false : pred(car(lat)) || any(pred, cdr(lat)); | |
} | |
function every(pred, lat) { | |
return !any(not(pred), lat) | |
} | |
function asArray(list) { | |
return isEmpty(list) ? [] : [car(list)].concat(asArray(cdr(list))); | |
} | |
function asList(arr) {return list.apply(null, arr);} | |
function flip(fn) { | |
return function(a, b) { return fn(b, a); }; | |
} | |
function lPartial(fn) { | |
var args = [].slice.call(arguments, 1); | |
return function() { | |
return fn.apply(this, args.concat([].slice.call(arguments))); | |
}; | |
} | |
function rPartial(fn) { | |
var args = [].slice.call(arguments, 1); | |
return function() { | |
return fn.apply(this, [].slice.call(arguments).concat(args)); | |
}; | |
} | |
function eq(l, r) { | |
return (l === null && r === null) || | |
(l === undefined && r === undefined) || | |
(atom(l) && atom(r) && l == r) || | |
(pair(l) && pair(r) && eq(car(l), car(r)) && eq(cdr(l), cdr(r))); | |
} |
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
var list1 = cons(1, (cons (3, (cons(5, (cons(7, null))))))); | |
console.assert(1 === car(list1), "car"); | |
console.assert(3 === car(cdr(list1)), "cdr"); | |
console.assert(atom(42) && atom(true) && atom(false) && atom({}) && atom("abc") && | |
atom(NaN) && atom([1, 2]) && atom([]), "atom"); | |
console.assert(!atom(list1) && !atom(null) && !atom(undefined), "not atom"); | |
console.assert(pair(list1), "pair"); | |
console.assert(!pair(42) && !pair(true) && !pair(false) && !pair({}) && !pair("abc") && | |
!pair(NaN) && !pair([1, 2]) && !pair([]), "not pair"); | |
console.assert("(1 3 5 7)" === "" + list1, "toString"); | |
console.assert("(3 5 7)" === "" + cdr(list1), "cdr toString"); | |
var list2 = list(1, 3, 6, 7); | |
console.assert("(1 3 6 7)" === "" + list2, "list"); | |
var times2 = function(x) {return 2 * x;}; | |
console.assert("(2 6 10 14)" === "" + map(times2, list1), "map"); | |
console.assert("hello" == foldl(function(a, b) {return a + b;}, "", | |
list("h", "e", "l", "l", "o")), "foldl"); | |
console.assert(12 == foldr(function(x, y) {return (x + y)/ 2;}, 54, list(12, 4, 10, 6)), "foldr"); | |
var odd = function(n) {return !!(n % 2);}; | |
var even = function(n) {return !(n % 2);}; | |
console.assert("(2 4)" === "" + filter(even, list(1, 2, 3, 4, 5)), "filter"); | |
console.assert("(1 2 3 4)" === "" + append(list(1, 2), list(3, 4)), "append"); | |
console.assert("(7 5 3 1)" === "" + reverse(list1), "reverse"); | |
console.assert(any(even, list2), "any even"); | |
console.assert(!any(even, list1), "not any even"); | |
console.assert(every(odd, list1), "every odd"); | |
console.assert(!every(odd, list2), "not every odd"); | |
var arr1 = asArray(list1); | |
console.assert("[object Array]" === Object.prototype.toString.call(arr1), "asArray type"); | |
console.assert("1,3,5,7" == arr1.toString(), "asArray"); | |
console.assert(pair(asList(arr1)), "asList type"); | |
console.assert("(1 3 5 7)" === "" + asList(arr1), "asList"); | |
console.assert("ba" === flip(function(x, y) {return x + y;})("a", "b"), "flip"); | |
var add = function(x, y) {return x + y}; | |
var sumAll = lPartial(foldl, add, 0); | |
console.assert(15 === sumAll(list(1, 2, 3, 4, 5)), "lPartial"); | |
var mult = function(x, y) {return x * y;}; | |
var firstFive = rPartial(foldl, list(1, 2, 3, 4, 5)); | |
console.assert(15 === firstFive(add, 0) && 120 === firstFive(mult, 1), "rPartial"); | |
console.assert(eq(list(1, 2, 3), list(1, 2, 3)), "eq"); | |
console.assert(!eq(list(1, 2, 3), list(1, 2, 3, 4)), "not eq"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks Mike, for getting this going -- so much fun!
Still would like to deal with asList([1, 2, [3, 4], 5]) // => (1 2 (3 4) 5) and the reverse for asArray().
All sorts of possible extensions, of course.