// to break up dependency cycles, type constructors are defined in their own JS module import { Type } from "../type.js"; import { DefaultMap } from "../util.js"; // Function type // The registry ensures that we never accidentally create more than one JS object for the same function type. // It is a cheap workaround for JS lacking customizable hash-functions and equality-testing-functions. // This same pattern is repeated throughout the code for all non-nullary type constructors (list, sum, product, ...) export const symbolFunction = Symbol('Function'); const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({ symbol: symbolFunction, params: [inType, outType], }))); // type constructor export const fnType = inType => outType => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true); // Convenience function. Wrapper around function below. export const typedFnType = (instance, callback) => { const [t, typesOfFns] = typedFnType2(callback); const res = [ { i: instance, t }, ...typesOfFns, ]; return res; }; // Convenience function. Creates a function type, and also create Type-links for the function type (being typed by Function) and for all the nested function types. Saves a lot of code writing. export const typedFnType2 = callback => { const fnTs = []; const wrappedFnType = inType => outType => { const fnT = fnType(inType)(outType); fnTs.push(fnT); return fnT; }; const t = callback(wrappedFnType); // force evaluation return [ t, fnTs.map(fnT => ({ i: fnT, t: Type })), ]; }; // Sum type export const symbolSum = Symbol("Sum"); const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({ symbol: symbolSum, params: [leftType, rightType], }))); // type constructor export const sumType = leftType => rightType => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true); // Product type export const symbolProduct = Symbol("Product"); const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({ symbol: symbolProduct, params: [leftType, rightType], }))); // type constructor export const prodType = leftType => rightType => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true); // List type export const symbolList = Symbol('List'); const listTypeRegistry = new DefaultMap(elementType => ({ symbol: symbolList, params: [elementType], })); // type constructor export const lsType = elementType => listTypeRegistry.getdefault(elementType, true);