Last active
September 26, 2018 14:44
-
-
Save friendlyanon/dfbd4747d3b1ed3bc48a0210200c4b0b to your computer and use it in GitHub Desktop.
This file contains hidden or 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
"use strict"; | |
// combine | |
function Combine(...iters) { | |
if (!new.target) { | |
return new Combine(...iters); | |
} | |
const { toString } = arguments; | |
for (const iter of iters) { | |
switch (toString.call(iter)) { | |
case "[object Combine]": | |
break; | |
case "[object Array]": | |
if (typeof iter[0] === "function") continue; | |
default: | |
throw new TypeError("illegal initializer list"); | |
} | |
} | |
this._iters = iters; | |
} | |
const Combine_eval = function() { | |
if (arguments.hasOwnProperty.call(this, "_memoizedResult")) { | |
return this._memoizedResult; | |
} | |
return this._memoizedResult = this._naked().next().value; | |
}; | |
const Combine_reEval = function() { | |
if (this._iters) delete this._memoizedResult; | |
return this.eval(); | |
}; | |
const Combine_naked = function() { | |
const { toString } = arguments; | |
let result; | |
for (const element of this._iters) { | |
if (!result) { | |
switch (toString.call(element)) { | |
case "[object Array]": | |
result = this._kickStart(element); | |
continue; | |
case "[object Combine]": | |
result = element._naked(); | |
continue; | |
default: | |
throw new TypeError("This instance was incorrectly initialized"); | |
} | |
} | |
const iter = this._kickStart(element); | |
iter.next(); | |
if ((iter.next(result)).done) { | |
throw new TypeError("Lazy generator not supported"); | |
} | |
result = iter; | |
} | |
return result; | |
}; | |
const Combine_kickStart = function(iter) { | |
const arg = iter[this._iterSymbol](); | |
return (0, arg.next().value)(...arg); | |
}; | |
Object.defineProperties(Combine.prototype, { | |
eval: { | |
value: Combine_eval, | |
writeable: true, | |
configurable: true | |
}, | |
reEval: { | |
value: Combine_reEval, | |
writeable: true, | |
configurable: true | |
}, | |
destroy: { | |
value: function() { this._iters = null; }, | |
writeable: true, | |
configurable: true | |
}, | |
_naked: { | |
value: Combine_naked, | |
writeable: true, | |
configurable: true | |
}, | |
_kickStart: { | |
value: Combine_kickStart, | |
writeable: true, | |
configurable: true | |
}, | |
_iterSymbol: { | |
value: Symbol.iterator, | |
writeable: true, | |
configurable: true | |
}, | |
[Symbol.toStringTag]: { | |
get: () => "Combine", | |
configurable: true | |
}, | |
}); | |
// functions | |
function* Integers(i = 0) { | |
i = Math.floor(i); | |
while (true) yield i++; | |
} | |
function* Take(i = 0) { | |
if (!i || i < 1) return; | |
const values = yield; | |
yield; | |
for (const value of values) { | |
yield value; | |
if (--i === 0) return; | |
} | |
} | |
function* Filter(compFn) { | |
const values = yield; | |
yield; | |
for (const value of values) { | |
if (compFn(value)) yield value; | |
} | |
} | |
function* Fold(foldFn, accumulator = 0) { | |
const values = yield; | |
yield; | |
for (const value of values) { | |
accumulator = foldFn(value, accumulator); | |
} | |
yield accumulator; | |
} | |
function* CollectList() { | |
const values = yield; | |
yield; | |
yield [...values]; | |
} | |
// usage | |
const expr = Combine( | |
[Integers], | |
[Take, 100], | |
[Filter, i => !(i % 2)] | |
); | |
console.log(Combine(expr, [CollectList]).eval()); | |
console.log(Combine(expr, [Fold, (i, a) => i + a]).eval()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment