greatly simplify type registry
This commit is contained in:
parent
303fa869a8
commit
4ca60784aa
3 changed files with 36 additions and 85 deletions
|
|
@ -1,19 +1,17 @@
|
||||||
import { Function, Type } from "../metacircular.js";
|
|
||||||
import { Double } from "../primitives/symbols.js";
|
import { Double } from "../primitives/symbols.js";
|
||||||
import { String } from "../structures/list_types/string.js";
|
|
||||||
import { nominalType, NominalType } from "../structures/nominal_type.js";
|
import { nominalType, NominalType } from "../structures/nominal_type.js";
|
||||||
import { makeProductType } from "../structures/product.js";
|
import { makeProductType } from "../structures/product.js";
|
||||||
import { fnType, prodType, typedFnType } from "../type_registry.js";
|
import { prodType, typedFnType } from "../type_registry.js";
|
||||||
|
|
||||||
const PointCartesian2D = nominalType(
|
const PointCartesian2D = nominalType(
|
||||||
// just a unique number, to make sure that our type is only equal to itself
|
|
||||||
"PointCartesian2D")
|
"PointCartesian2D")
|
||||||
|
// just a unique number, to make sure that our type is only equal to itself
|
||||||
// BigInt("0xBBAAD62B10EE21993BA690A732DA2A6875CE4B6F5E7139D5AEC9FD887F9D24A8"))
|
// BigInt("0xBBAAD62B10EE21993BA690A732DA2A6875CE4B6F5E7139D5AEC9FD887F9D24A8"))
|
||||||
(prodType(Double, Double));
|
(prodType(Double, Double));
|
||||||
|
|
||||||
const PointPolar2D = nominalType(
|
const PointPolar2D = nominalType(
|
||||||
// just a unique number, to make sure that our type is only equal to itself
|
|
||||||
"PointPolar2D")
|
"PointPolar2D")
|
||||||
|
// just a unique number, to make sure that our type is only equal to itself
|
||||||
// BigInt("0x31CDAB4B3D84C4EB27D3C111FD7580E533268B72E05BD694F8B262913E018B72"))
|
// BigInt("0x31CDAB4B3D84C4EB27D3C111FD7580E533268B72E05BD694F8B262913E018B72"))
|
||||||
(prodType(Double, Double));
|
(prodType(Double, Double));
|
||||||
|
|
||||||
|
|
|
||||||
111
type_registry.js
111
type_registry.js
|
|
@ -1,94 +1,47 @@
|
||||||
// This module ensures that we never accidentally create a Symbol for the same type twice.
|
// This module ensures that we never accidentally create more than one JS object for the same type twice.
|
||||||
// Maybe we shouldn't use Symbols for types, but we also cannot use primitive values for types because they may accidentally overlap with 'real' values (that are not types)
|
// We do so by creating (nested) DefaultMap(s) for all non-nullary type constructors
|
||||||
// We also cannot use objects for types because similar to Symbols, objects are only equal to themselves if we use them as Map keys.
|
// It is a cheap workaround for JS lacking customizable hash-functions and equality-testing-functions.
|
||||||
|
|
||||||
import { Function } from "./metacircular.js";
|
import { Function } from "./metacircular.js";
|
||||||
import { DefaultMap } from "./util.js";
|
import { DefaultMap } from "./util.js";
|
||||||
|
|
||||||
// Global store of function types:
|
|
||||||
const fnTypes = new DefaultMap(() => new Map());
|
|
||||||
export const fnType = ({in: inType, out: outType}) => {
|
|
||||||
const m2 = fnTypes.getdefault(inType, true);
|
|
||||||
if (m2.has(outType)) {
|
|
||||||
return m2.get(outType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const fnType = {in: inType, out: outType};
|
|
||||||
m2.set(outType, fnType);
|
|
||||||
return fnType;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const listTypeRegistry = new DefaultMap(elementType => ({listOf: elementType}));
|
||||||
|
const genericTypeRegistry = new DefaultMap(underlyingType => ({generic: underlyingType}));
|
||||||
|
const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({in: inType, out: outType})));
|
||||||
|
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({operator: "product", leftType, rightType})));
|
||||||
|
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({operator: "sum", leftType, rightType})));
|
||||||
|
|
||||||
|
|
||||||
|
export const lsType = listTypeRegistry.getdefault.bind(listTypeRegistry);
|
||||||
|
export const genericType = genericTypeRegistry.getdefault.bind(genericTypeRegistry);
|
||||||
|
export const fnType = ({in: inType, out: outType}) => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true);
|
||||||
|
export const sumType = (leftType, rightType) => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||||
|
export const prodType = (leftType, rightType) => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||||
|
|
||||||
|
|
||||||
|
// Wrapper around function below.
|
||||||
export const typedFnType = (instance, callback) => {
|
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 fnTs = [];
|
||||||
const wrappedFnType = ({in: inType, out: outType}) => {
|
const wrappedFnType = ({in: inType, out: outType}) => {
|
||||||
|
console.log('wrappedFnType called')
|
||||||
const fnT = fnType({in: inType, out: outType});
|
const fnT = fnType({in: inType, out: outType});
|
||||||
fnTs.push(fnT);
|
fnTs.push(fnT);
|
||||||
return fnT;
|
return fnT;
|
||||||
}
|
}
|
||||||
|
const t = callback(wrappedFnType); // force evaluation
|
||||||
return [
|
return [
|
||||||
{i: instance, t: callback(wrappedFnType)},
|
t,
|
||||||
...fnTs.map(fnT => ({i: fnT, t: Function})),
|
fnTs.map(fnT => ({i: fnT, t: Function})),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global store of list types:
|
|
||||||
const listTypes = new Map();
|
|
||||||
export const lsType = (elementType) => {
|
|
||||||
if (listTypes.has(elementType)) {
|
|
||||||
// only generate each list type once
|
|
||||||
// this would not be necessary if we could define our own equality and hash functions on objects in JavaScript.
|
|
||||||
return listTypes.get(elementType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const type = {
|
|
||||||
listOf: elementType,
|
|
||||||
};
|
|
||||||
listTypes.set(elementType, type);
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global store of product types:
|
|
||||||
const productTypes = new DefaultMap(() => new Map());
|
|
||||||
export const prodType = (leftType, rightType) => {
|
|
||||||
const m2 = productTypes.getdefault(leftType, true);
|
|
||||||
if (m2.has(rightType)) {
|
|
||||||
return m2.get(rightType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const pt = Symbol(`${leftType.toString()} × ${rightType.toString()}`);
|
|
||||||
m2.set(rightType, pt);
|
|
||||||
return pt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global store of sum types:
|
|
||||||
const sumTypes = new DefaultMap(() => new Map());
|
|
||||||
export const sumType = (leftType, rightType) => {
|
|
||||||
const m2 = sumTypes.getdefault(leftType, true);
|
|
||||||
if (m2.has(rightType)) {
|
|
||||||
return m2.get(rightType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const st = Symbol(`${leftType.toString()} + ${rightType.toString()}`);
|
|
||||||
m2.set(rightType, st);
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// const genericTypes = new Map();
|
|
||||||
// export const genericType = (underlyingType) => {
|
|
||||||
// if (genericTypes.has(underlyingType)) {
|
|
||||||
// // only generate each list type once
|
|
||||||
// // this would not be necessary if we could define our own equality and hash functions on objects in JavaScript.
|
|
||||||
// return genericTypes.get(underlyingType);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// const type = {
|
|
||||||
// generic: underlyingType,
|
|
||||||
// };
|
|
||||||
// genericTypes.set(underlyingType, type);
|
|
||||||
// return type;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
2
util.js
2
util.js
|
|
@ -30,7 +30,7 @@ export class DefaultMap {
|
||||||
}
|
}
|
||||||
getdefault(key, addToMapping=false) {
|
getdefault(key, addToMapping=false) {
|
||||||
return this.m.get(key) || (() => {
|
return this.m.get(key) || (() => {
|
||||||
const val = this.defaultValue();
|
const val = this.defaultValue(key);
|
||||||
if (addToMapping)
|
if (addToMapping)
|
||||||
this.m.set(key, val);
|
this.m.set(key, val);
|
||||||
return val;
|
return val;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue