import { Bottom, Int, Unit } from "../primitives/types.js"; import { unit } from "../primitives/unit.js"; import { capitalizeFirstLetter } from "../util/util.js"; import { constructorProduct, getLeft, getRight } from "./product.js"; import { constructorLeft, constructorRight, match } from "./sum.js"; import { lsType, prettyT, sumType } from "./types.js"; // 'variants' is an array of (name: string, type: Type) pairs. // e.g., the list of variants: // [ { l: "price" , r: Int }, // { l: "prices" , r: [Int] }, // { l: "not_found", r: Unit } ] // results in the type: // (Int | ([Int] | (Unit | ⊥))) export const enumType = variants => { if (variants.length === 0) { return Bottom; // empty enum is equal to Bottom-type (cannot be instantiated) } const [variant, ...rest] = variants; const variantType = getRight(variant); return sumType(variantType)(enumType(rest)); }; const eatParameters = (numParams, result) => { if (numParams === 0) { return result; } else return () => eatParameters(numParams-1, result); } export const makeMatchFn = variants => { if (variants.length === 0) { return undefined; } const [_, ...remainingVariants] = variants; return sum => handler => { return ( match(sum)(constructorProduct (leftValue => eatParameters(remainingVariants.length, handler(leftValue))) (rightValue => makeMatchFn(remainingVariants)(rightValue)) )); }; }; export const makeConstructors = variants => { if (variants.length === 0) { return []; } const [variant, ...remainingVariants] = variants; const name = getLeft(variant); const ctorName = `new${capitalizeFirstLetter(name)}`; const constructor = { [ctorName]: val => constructorLeft(val) }[ctorName]; return [ constructor, ...makeConstructors(remainingVariants).map(ctor => ({[ctor.name]: val => constructorRight(ctor(val))}[ctor.name])), ]; } /////////////////////////////////////////////////////////////////////////////// const variants = [ constructorProduct("price")(Int), constructorProduct("prices")(lsType(Int)), constructorProduct("not_found")(Unit), ]; const myEnum = enumType(variants); console.log(prettyT(myEnum)); const [newPrice, newPrices, newNotFound] = makeConstructors(variants); console.log(newPrice(10)); console.log(newPrices([20,30])); console.log(newNotFound(unit)); const myMatchFn = makeMatchFn(variants); const matchVariant = x => myMatchFn(x) (price => `Price: ${price}`) (prices => `Prices: ${prices}`) (() => "Not found!"); console.log(matchVariant(newPrice(10))); console.log(matchVariant(newPrices([20,30]))); console.log(matchVariant(newNotFound(unit)));