ts-union
Version:
ADT (sum type) in typescript inspired by ML language family
90 lines (88 loc) • 2.97 kB
JavaScript
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;
export { Union, of };
//# sourceMappingURL=index.js.map