Skip to content

Instantly share code, notes, and snippets.

@friendlyanon
Last active September 26, 2018 14:44
Show Gist options
  • Save friendlyanon/dfbd4747d3b1ed3bc48a0210200c4b0b to your computer and use it in GitHub Desktop.
Save friendlyanon/dfbd4747d3b1ed3bc48a0210200c4b0b to your computer and use it in GitHub Desktop.
"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