Last active
February 16, 2018 13:19
-
-
Save indongyoo/4f7914e120aeb600a84face376526fba 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
function then(f, a) { | |
return arguments.length == 1 ? | |
a => then(f, a) : | |
a instanceof Promise ? a.then(f) : f(a); | |
} | |
function toIterator(data) { | |
if (data == null) data = []; | |
if (!data[Symbol.iterator]) data = Object.values(data); | |
return data[typeof data.values == 'function' ? 'values' : Symbol.iterator](); | |
} | |
function reduceIter(f, acc, iter) { | |
return then(function recur(acc) { | |
for (const val of iter) | |
if ((acc = f(acc, val)) instanceof Promise) | |
return acc.then(recur); | |
return acc; | |
}, acc); | |
} | |
function curry2(f) { | |
return function(a) { | |
return arguments.length > 1 ? f(...arguments) : function() { return f(a, ...arguments); } | |
} | |
} | |
const reduce = curry2(function(f, data) { | |
const iter = toIterator(data); | |
return reduceIter(f, iter.next().value, iter) | |
}); | |
const reduceAcc = curry2(function(f, acc, data) { | |
return arguments.length == 2 ? | |
data => reduceAcc(f, clone(acc), data) : | |
reduceIter(f, acc, toIterator(data)); | |
}); | |
function clone(data) { | |
if (data == null || typeof data != 'object') return data; | |
return Array.isArray(data) ? [...data] : Object.assign({}, data); | |
} | |
function call(f, arg) { | |
return callRight(arg, f); | |
} | |
function callRight(arg, f) { | |
return arg instanceof Tuple ? f(...arg) : arg === undefined ? f() : f(arg); | |
} | |
function go() { | |
return reduce(callRight, arguments); | |
} | |
function pipe(...fs) { | |
return function() { | |
return reduceAcc(callRight, toTuple(arguments), fs); | |
}; | |
} | |
class Tuple { | |
constructor() { | |
this.value = arguments; | |
} | |
[Symbol.iterator]() { | |
return this.value[Symbol.iterator](); | |
} | |
} | |
function tuple(...args) { | |
if (args.length == 1) return args[0]; | |
return find(arg => arg instanceof Promise, args) ? | |
then(toTuple, Promise.all(args)) : | |
new Tuple(...args); | |
} | |
function toTuple(list) { | |
return list.length == 1 ? list[0] : new Tuple(...list); | |
} | |
function find(f, data) { | |
if (arguments.length == 1) return data => find(f, data); | |
const iter = toIterator(data); | |
return function recur(bool) { | |
for (const val of iter) | |
if (bool = f(val)) | |
return then(b => b ? val : recur(), bool); | |
} (); | |
} | |
const isUndefined = val => val === undefined; | |
const not = bool => !bool; | |
const negate = f => pipe(f, not); | |
const _none = pipe(find, isUndefined), | |
none = curry2(_none); | |
const some = curry2(negate(_none)); | |
const every = curry2(pipe((f, data) => find(negate(f), data), isUndefined)); | |
const append = curry2(function(list, item) { | |
return list.push(item), list; | |
}); | |
const map = curry2(function(f, data) { | |
return reduceAcc((list, val) => go(val, f, append(list)), [], data); | |
}); | |
const cmap = curry2(function(f, data) { | |
return Promise.all(reduceAcc((list, val) => append(list, f(val)), [], data)); | |
}); | |
const each = curry2(function(f, data) { | |
return reduceAcc((nil, val) => f(val), null, data); | |
}); | |
function unless(...fs) { | |
var f = cond(...fs)(tuple); | |
return function(...fs) { | |
return f.else(...fs); | |
}; | |
} | |
function cond() { | |
var pbs = []; | |
function predicate(f) { | |
pbs.push({ | |
predicate: typeof f == 'function' ? pipe(...arguments) : b => b == f | |
}); | |
return body; | |
} | |
function body() { | |
pbs[pbs.length-1].body = pipe(...arguments); | |
return predicate; | |
} | |
predicate.else = function() { | |
predicate(() => true) (...arguments); | |
return evaluator; | |
}; | |
var evaluator = pipe(function() { | |
return go(pbs, | |
find(pb => pb.predicate(...arguments)), | |
pb => pb.body(...arguments)); | |
}); | |
return predicate(...arguments); | |
} | |
function tap(f) { | |
return function() { | |
return go(f(...arguments), _=> toTuple(arguments)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment