Skip to content

Instantly share code, notes, and snippets.

@datchley
Last active August 29, 2015 14:13
Show Gist options
  • Save datchley/f5f4eaf1a6e0b198b1b5 to your computer and use it in GitHub Desktop.
Save datchley/f5f4eaf1a6e0b198b1b5 to your computer and use it in GitHub Desktop.
Functional Programming Concepts - Javascript
var slice = Array.prototype.slice,
join = Array.prototype.join,
concat = Array.prototype.concat,
toString = Object.prototype.toString,
isString = function(o){ return toString.call(o) == '[object String]'; },
isArray = function(o) { return toString.call(o) == '[object Array]'; };
// I Combinator
var identity = function(x){ return x; };
// K Combinator
var kestrel = function(x) { return (function(y){ return x; }) };
// convert argument to array (useful for arguments w/in functions)
var toArray = function(a){ return [].slice.call(a); };
// Compose: f(g(x)) for variable number of arguments (recursive)
function compose() {
var args = [].slice.call(arguments),
fn = args.shift(),
gn = args.shift(),
fog = gn ? function() { return fn(gn.apply(this, arguments)); } : fn;
return args.length ? compose.apply(this, [fog].concat(args)) : fog;
}
// Reverse the arguments to a function
function flip(fn) {
return function() {
var args = [].slice.call(arguments);
return fn.apply(this, args.reverse());
};
}
// modify a function to only run once
function once(fn) {
var done = false;
return function() {
return done ? void 0 : ((done = true), fn.apply(this, arguments));
}
}
// Do something with a value and pass the value on
function tap(val) {
return function(fn) {
if (typeof(fn) === 'function') {
fn(val);
}
return val;
}
}
// Convert a function to only use one argument
function unary (fn) {
if (fn.length == 1) { return fn; }
else {
return function (something) {
return fn.call(this, something);
}
}
}
// Curry one argument
function curry(fn) {
return function(arg) {
return fn(arg);
};
}
// Curry two arguments, right to left
function curry2(fn) {
return function(secondArg) {
return function(firstArg) {
return fn(firstArg, secondArg);
};
};
}
// Drop n number of elements from a list, or just 1st
function drop(list, n) {
return [].slice.call(list, n || 1);
}
// Drop the first 2 elements from a list
var drop2 = curry2(2);
drop2([1,2,3,4]);
// => [3,4]
// Partially apply arbitrary number of arguments from left to right
function partial(fn /*, pargs */) {
var pargs = drop(arguments);
return function(/* arguments */) {
var args = pargs.concat(toArray(arguments));
return fn.apply(fn, args);
};
}
function flatMap(list, fn) {
return concat.apply([], map(list, function(o) {
return isArray(o) ? flatMap(o, fn) : fn(o);
})
);
}
function applyWith(/* fns */){
var fns = slice.call(arguments);
return function(/* args */) {
var args = slice.call(arguments)
return map(fns, function(fn) {
return fn.apply(fn, args);
});
};
},
var slice = Array.prototype.slice,
join = Array.prototype.join,
concat = Array.prototype.concat,
toString = Object.prototype.toString,
isString = function(o){ return toString.call(o) == '[object String]'; },
isArray = function(o) { return toString.call(o) == '[object Array]'; },
identity = function(v) { return v; },
asArray = function(arg) {
if (isArray(arg)) {
return arg;
}
if (isString(arg)) {
return arg.split('');
}
return [arg];
},
flatMap = function(list, fn) {
return concat.apply([], map(list, function(o) {
return isArray(o) ? flatMap(o, fn) : fn(o);
})
);
},
partial = function(fn) {
var pargs = slice.call(arguments, 1);
return function(/* args */) {
var args = slice.call(arguments);
return fn.apply(fn, pargs.concat(args));
};
},
map = function(list, fn) {
var ret = [], len = list.length;
for (var i=0; i < len; i++) {
ret.push(fn(list[i]));
}
return ret;
},
mapWith = function(fn) {
return function(list) {
return map(list, fn);
};
},
apply = function(fnlist /* args */) {
var args = slice.call(arguments, 1);
return map(fnlist, function(fn) {
return fn.apply(this, args);
});
},
applyWith = function(/* args */){
var args = slice.call(arguments);
return function(fnlist) {
return apply.apply(null, [fnlist].concat(args));
};
},
range = function(s,e){
var ret = [];
for (var i=s; i<=e; i++) ret.push(i);
return ret;
},
choose = function(fn, tval, fval) {
return function(/* args */) {
var args = slice.call(arguments);
return fn.apply(fn, args) ? tval : fval;
};
},
accrete = function accrete(seed /* args */) {
var args = slice.call(arguments,1);
if (!args.length) {
return seed;
}
return seed + accrete.apply(this, args);
}
//
// application specific functions
//
divBy = function(d, n) { return n % d === 0; },
fizz = choose(partial(divBy, 3), 'fizz', ''),
buzz = choose(partial(divBy, 5), 'buzz', ''),
bang = choose(partial(divBy, 7), 'bang', ''),
fizzbuzz = mapWith(function(n) {
return mapWith(function(n) {
return accrete(fizz(n),buzz(n),bang(n));
})([n])[0] || n;
});
// Test Fizz-Buzz-Bang
fizzbuzz(range(1,105));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment