// to break up dependency cycles, type constructors are defined in their own JS module import { Type } from "../primitives/types.js"; import { getSymbol, makeTypeConstructor } from "../type_constructor.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'); export const fnType = makeTypeConstructor(symbolFunction)(2); export const isFunction = type => getSymbol(type) === symbolFunction; // 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 typedFnType = (instance, callback, typeOfType = Type) => { const fnTs = []; const wrappedFnType = inType => outType => { const fnT = fnType(inType)(outType); fnTs.push(fnT); return fnT; }; const t = callback(wrappedFnType); // force evaluation if (t.typeVars && typeOfType === Type) { throw new Error("you probably meant to create a GenericType"); } const res = [ { i: instance, t }, { i: t , t: typeOfType }, // ...fnTs.map(fnT => ({ i: fnT, t: Type })), ]; return res; }; // Sum type export const symbolSum = Symbol("Sum"); export const sumType = makeTypeConstructor(symbolSum)(2); // Product type export const symbolProduct = Symbol("Product"); export const prodType = makeTypeConstructor(symbolProduct)(2); // List type export const symbolList = Symbol('List'); export const lsType = makeTypeConstructor(symbolList)(1); // Set type export const symbolSet = Symbol('Set'); export const setType = makeTypeConstructor(symbolSet)(1);