ts-union
Version:
ADT (sum type) in typescript inspired by ML language family
124 lines (93 loc) • 2.87 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
const of = val => val;
const Union = recOrFunc => {
const record = typeof recOrFunc === 'function' ? recOrFunc(undefined) : recOrFunc; // tslint:disable-next-line:prefer-object-spread
return Object.assign({
if: createUnpack(record),
match: (a, b) => b ? evalMatch(a, b) : val => evalMatch(val, a),
matchWith: (_other, // yep, it is only used to "remember" type
matchObj) => createMatchTupleFunction(matchObj)
}, createConstructors(record, typeof recOrFunc === 'function'));
};
const createMatchTupleFunction = matchObj => {
const {
default: def
} = matchObj;
return function matchTuple(a, b) {
const {
p0: valA,
k: keyA
} = a;
const {
p0: valB,
k: KeyB
} = b;
if (keyA in matchObj) {
const inner = matchObj[keyA];
if (inner !== undefined && KeyB in inner) {
const matchedFunction = inner[KeyB];
if (matchedFunction !== undefined) {
return matchedFunction(valA, valB);
}
}
}
return def(a, b);
};
};
const evalMatch = (val, cases) => {
// first elem is always the key
const handler = cases[getKey(val)];
return handler ? invoke(val, handler) : cases.default && cases.default(val);
};
const createConstructors = (rec, isGeneric) => {
const result = {}; // tslint:disable-next-line: forin
for (const key in rec) {
result[key] = createCtor(key, rec, isGeneric);
}
return result;
};
const createCtor = (key, rec, isGeneric) => {
const val = rec[key]; // it means that it was constructed with of(null)
if (val === null) {
const frozenVal = Object.freeze(makeValue(key, undefined, undefined, undefined));
return isGeneric ? () => frozenVal : frozenVal;
} // tslint:disable-next-line:no-if-statement
if (val !== undefined) {
const res = makeValue(key, val, undefined, undefined);
return () => res;
}
return (p0, p1, p2) => makeValue(key, p0, p1, p2);
};
const createUnpack = rec => {
const result = {}; // tslint:disable-next-line:forin
for (const key in rec) {
result[key] = createUnpackFunc(key);
}
return result;
};
const createUnpackFunc = key => (val, f, els) => getKey(val) === key ? invoke(val, f) : els && els(val);
const makeValue = (k, p0, p1, p2) => ({
k,
p0,
p1,
p2,
a: arity(p0, p1, p2)
});
const invoke = (val, f) => {
switch (val.a) {
case 0:
return f();
case 1:
return f(val.p0);
case 2:
return f(val.p0, val.p1);
case 3:
return f(val.p0, val.p1, val.p2);
}
};
const getKey = val => val.k; // const getParams = (val: any) => val.p;
const arity = (p0, p1, p2) => p2 !== undefined ? 3 : p1 !== undefined ? 2 : p0 !== undefined ? 1 : 0;
exports.Union = Union;
exports.of = of;
//# sourceMappingURL=index.js.map