dope2/structures/types.js

87 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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);
// Pretty print type
export function prettyT(type) {
// console.log("pretty:", type);
if (typeof type === "symbol") {
return type.description;
}
if (type.typeVars) {
if (type.typeVars.size > 0) {
return `${[...type.typeVars].map(prettyT).sort((a,b)=>a.localeCompare(b)).join(",")}: ${prettyT(type.type)}`;
}
else {
return prettyT(type.type);
}
}
if (type.symbol === symbolFunction) {
return `(${prettyT(type.params[0])} -> ${prettyT(type.params[1])})`;
}
if (type.symbol === symbolList) {
return `[${prettyT(type.params[0])}]`;
}
if (type.symbol === symbolProduct) {
return `(${prettyT(type.params[0])} × ${prettyT(type.params[1])})`;
}
if (type.symbol === symbolSum) {
return `(${prettyT(type.params[0])} | ${prettyT(type.params[1])})`;
}
if (type.params.length === 0) {
return type.symbol.description;
}
return `${type.symbol.description}(${type.params.map(prettyT).join(", ")})`;
}