import { DefaultMap } from "../util.js"; const symbolFunction = Symbol('Function'); // 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, ...) const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({ symbol: symbolFunction, params: [inType, outType], }))); // type constructor for function types export const fnType = inType => outType => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true); // Wrapper around function below. export const typedFnType = (instance, callback) => { const [t, typesOfFns] = typedFnType2(callback); const res = [ { i: instance, t }, ...typesOfFns, ]; return res; }; // Create 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 = ({ in: inType, out: outType }) => { const fnT = fnType({ in: inType, out: outType }); fnTs.push(fnT); return fnT; }; const t = callback(wrappedFnType); // force evaluation return [ t, fnTs.map(fnT => ({ i: fnT, t: Function })), ]; }; export const ModuleFunction = {l:[ // binary type constructor: Type -> Type -> Type ...typedFnType(fnType, fnType => fnType /* in */ (Type) /* out */ (fnType /* in */ (Type) /* out */ (Type) ) ), ]};