UNPKG

purelogic-ts

Version:
394 lines (393 loc) 12.8 kB
"use strict"; require("tslib"); const iterable = require("iterable-ts"); class CacheMap { constructor() { this._map = {}; } set(id, value) { this._map[id] = value; } get(id, create) { const result = this._map[id]; if (result === undefined) { const newResult = create(); this._map[id] = newResult; return newResult; } return result; } } exports.CacheMap = CacheMap; /** * Bag type and related functions. */ var bag; (function (bag_1) { class FlatMap { constructor(input, func) { this.input = input; this.func = func; } } bag_1.FlatMap = FlatMap; class DisjointUnion { constructor(a, b) { this.a = a; this.b = b; } } bag_1.DisjointUnion = DisjointUnion; class GroupBy { constructor(input, toKey, reduce) { this.input = input; this.toKey = toKey; this.reduce = reduce; } } bag_1.GroupBy = GroupBy; class Product { constructor(a, b, func) { this.a = a; this.b = b; this.func = func; } } bag_1.Product = Product; class Dif { constructor(value, a, b) { this.value = value; this.a = a; this.b = b; } } bag_1.Dif = Dif; function one(value) { return new Bag((visitor) => visitor.one(value)); } bag_1.one = one; function input() { return new Bag((visitor) => visitor.input()); } bag_1.input = input; function range(a, b) { return one(null).flatMap(() => iterable.range(a, b)); } bag_1.range = range; let bagCounter = 0; class Join { constructor(key, a, b) { this.key = key; this.a = a; this.b = b; } } bag_1.Join = Join; class Bag { constructor(implementation) { this.implementation = implementation; this.id = bagCounter.toString(); ++bagCounter; } /** * LINQ: SelectMany */ flatMap(func) { return new Bag((visitor) => visitor.flatMap(new FlatMap(this, func))); } disjointUnion(b) { return new Bag((visitor) => visitor.disjointUnion(new DisjointUnion(this, b))); } /** * LINQ: GroupBy */ groupBy(toKey, reduce) { return new Bag((visitor) => visitor.groupBy(new GroupBy(this, toKey, reduce))); } product(b, func) { return new Bag((visitor) => visitor.product(new Product(this, b, func))); } /** * LINQ: Select */ map(func) { return this.flatMap(value => [func(value)]); } /** * LINQ: Where */ filter(func) { return this.flatMap(iterable.filterFuncToFlatMapFunc(func)); } compact() { return this.filter(Boolean); } /** * LINQ: Accumulate */ reduce(func) { return this.groupBy(() => "", func); } dif(b) { const toDif = (bag, a, b) => bag.map(v => new Dif(v, a, b)); const aDif = toDif(this, 1, 0); const bDif = toDif(b, 0, 1); return aDif.disjointUnion(bDif).groupBy(v => JSON.stringify(v.value), (x, y) => new Dif(x.value, x.a + y.a, x.b + y.b)); } join(b, keyT, keyB, reduceT, reduceB) { function join(k, t, b) { return new Join(k, t, b); } const bagT = this.map(x => join(keyT(x), x, undefined)); const bagB = b.map(x => join(keyB(x), undefined, x)); const bagC = bagT.disjointUnion(bagB); function reduceOptional(reduce) { return (x, y) => { if (x === undefined) { return y; } if (y === undefined) { return x; } return reduce(x, y); }; } return bagC.groupBy(x => x.key, (x, y) => join(x.key, reduceOptional(reduceT)(x.a, y.a), reduceOptional(reduceB)(x.b, y.b))); } } bag_1.Bag = Bag; })(bag = exports.bag || (exports.bag = {})); /** * Optimized graph. */ var optimized; (function (optimized) { class Node { constructor(id, implementation) { this.id = id; this.implementation = implementation; } link(func) { const value = new LinkValue(this, func); return new Link((visitor) => visitor(value)); } bag() { return new Bag(this.id, [this.link(iterable.flatMapIdentity)]); } } optimized.Node = Node; class LinkValue { constructor(node, func) { this.node = node; this.func = func; } } optimized.LinkValue = LinkValue; class Link { constructor(implementation) { this.implementation = implementation; } nodeId() { return this.implementation((x) => x.node.id); } flatMap(func) { function visitor(x) { const f = x.func; const newFunc = f !== iterable.flatMapIdentity ? (value) => iterable.toArray(iterable.flatMap(f(value), func)) : func; return x.node.link(newFunc); } return this.implementation(visitor); } addFunc(getFunc) { function visitor(link) { const f = link.func; const fNew = getFunc(); return link.node.link(i => iterable.concat(f(i), fNew(i))); } return this.implementation(visitor); } } optimized.Link = Link; class Bag { constructor(id, links) { this.id = id; this.links = links; } linksMap(visitor) { return this.links.map(link => link.implementation(visitor)); } groupBy(id, toKey, reduce) { return new Node(id, (visitor) => visitor.groupBy(this, toKey, reduce)) .bag(); } product(id, b, func) { return new Node(id, (visitor) => visitor.product(this, b, func)) .bag(); } flatMap(id, func) { return new Bag(id, this.links.map(link => link.flatMap(func))); } disjointUnion(id, b) { const c = iterable.concat(this.links, b.links); const g = iterable.groupBy(c, x => x.nodeId(), (x, y) => { function visitor(v) { function getFunc() { return v.func; } return x.addFunc(getFunc); } return y.implementation(visitor); }); return new Bag(id, iterable.toArray(iterable.values(g))); } } optimized.Bag = Bag; function input(id) { return new Node(id, (visitor) => visitor.input()).bag(); } optimized.input = input; function one(id, value) { return new Node(id, (visitor) => visitor.one(value)).bag(); } optimized.one = one; /** * DAG */ class Dag { constructor() { this._map = new CacheMap(); } get(b) { const id = b.id; return this._map.get(id, () => { const getOpimized = (b) => this.get(b); class Visitor { flatMap(value) { return getOpimized(value.input).flatMap(id, value.func); } disjointUnion(value) { return getOpimized(value.a).disjointUnion(id, getOpimized(value.b)); } one(value) { return optimized.one(id, value); } input() { return optimized.input(id); } groupBy(value) { return getOpimized(value.input).groupBy(id, value.toKey, value.reduce); } product(value) { return getOpimized(value.a).product(id, getOpimized(value.b), value.func); } } return b.implementation(new Visitor()); }); } } optimized.Dag = Dag; })(optimized = exports.optimized || (exports.optimized = {})); class InputError { constructor(bagId) { this.bagId = bagId; this.name = "InputError"; this.message = `InputError: input bag ${bagId} is not defined`; } } exports.InputError = InputError; class Mem { constructor() { this._map = new CacheMap(); this._dag = new optimized.Dag(); } } exports.Mem = Mem; /** * Synchronous memory back-end. */ class SyncMem extends Mem { set(input, factory) { this._map.set(input.id, factory); } get(b) { return this._get(this._dag.get(b)); } _get(o) { const id = o.id; return this._map.get(id, () => { // NOTE: possible optimization: // if (value.func === flatMap.identity) { return nodeFunc; } const links = o.linksMap((value) => iterable.flatMap(this._fromNode(value.node), value.func)); // NOTE: possible optimization: if (links.lenght === 1) { newResult = links[0]; } return iterable.flatten(links); }); } _fromNode(n) { const id = n.id; const map = this._map; return map.get(id, () => { const get = (b) => this._get(b); class Visitor { /** * when input is not defined yet. */ input() { throw new InputError(id); } one(value) { return [value]; } groupBy(input, toKey, reduce) { return iterable.values(iterable.groupBy(get(input), toKey, reduce)); } product(a, b, func) { return iterable.product(get(a), get(b), func); } } return n.implementation(new Visitor()); }); } } exports.SyncMem = SyncMem; class AsyncMem extends Mem { set(input, getArray) { this._map.set(input.id, getArray); } get(b) { return this._get(this._dag.get(b)); } _get(o) { const id = o.id; return this._map.get(id, () => __awaiter(this, void 0, void 0, function* () { // NOTE: possible optimization: // if (value.func === flatMap.identity) { return nodeFunc; } const linkPromises = o.linksMap((value) => __awaiter(this, void 0, void 0, function* () { return iterable.flatMap(yield this._fromNode(value.node), value.func); })); // NOTE: possible optimization: if (links.lenght === 1) { newResult = links[0]; } return iterable.flatten(yield Promise.all(linkPromises)); })); } _fromNode(n) { const id = n.id; const map = this._map; return map.get(id, () => { const get = (b) => this._get(b); class Visitor { input() { return Promise.reject(new InputError(id)); } one(value) { return __awaiter(this, void 0, void 0, function* () { return [value]; }); } groupBy(input, toKey, reduce) { return __awaiter(this, void 0, void 0, function* () { const i = yield get(input); return iterable.values(yield iterable.async.groupBy(i, toKey, reduce)); }); } product(a, b, func) { return __awaiter(this, void 0, void 0, function* () { return iterable.product(yield get(a), yield get(b), func); }); } } return n.implementation(new Visitor()); }); } } exports.AsyncMem = AsyncMem;