refactor code: move everything from type_registry to "most appropriate" modules

This commit is contained in:
Joeri Exelmans 2025-03-20 18:12:30 +01:00
parent 4ca60784aa
commit 5283be608b
22 changed files with 160 additions and 164 deletions

View file

@ -1,33 +0,0 @@
// import {Type, Function, makeTypedFnInOut, fnOut} from "../metacircular.js";
// import {Bool} from "../primitives/symbols.js";
// export const Conformable = Symbol('Conformable');
// export const conformanceCheck = Symbol('conformanceCheck');
// export const ModuleConformable = [
// {i: Conformable , t: Type},
// {i: conformanceCheck, t: Function},
// // Note: outType is just 'Type', we cannot use Bool because a function that has type 'conformanceCheck' will have outType Bool, therefore conformanceCheck must return the type of Bool, which is Type.
// ...makeTypedFnInOut({f: conformanceCheck, inType: Conformable, outType: Type}),
// ];
// ////////////////////////////////////////////////////////
// // Conformance check functions are themselves conformance checkable
// // This is because we want to restrict their return type to Bool
// const conformanceCheckIsConform = fn => {
// return fnOut(fn) === Bool;
// };
// const conformanceCheckIsConformFn = {name: "isConform", inType: conformanceCheck, outType: Bool, fn: conformanceCheckIsConform};
// export const ModuleConformanceCheckConforms = [
// // instances of conformanceCheck (= 'isConform'-functions) are themselves conformance checkable
// {i: conformanceCheck, t: Conformable},
// {i: conformanceCheckIsConformFn, t: conformanceCheck},
// {i: conformanceCheckIsConformFn, t: Function},
// ];

View file

@ -1,52 +1,54 @@
// import {Type, Function, makeTypedFnInOut, fnIn, fnOut} from "../metacircular.js";
// import {Conformable, conformanceCheck} from "./conformable.js";
// import {Bool} from "../primitives/symbols.js";
// import {deepEqual} from "../util.js";
import { makeGeneric } from "../generics/generics";
import { addDouble, mulDouble } from "../primitives/double";
import { addInt, mulInt } from "../primitives/int";
import { typedFnType, typedFnType2 } from "../metacircular";
// export const Num = Symbol('Num');
// export const NumDict = Symbol('NumDict');
// // export const addType = Symbol('addType');
// // export const addBoundType = Symbol('addBoundType');
// // export const mulType = Symbol('mulType');
// // export const mulBoundType = Symbol('mulBoundType');
const numDictTypeRegistry = new DefaultMap(a => ({numDict: a}));
export const numDictType = a => numDictTypeRegistry.getdefault(a, true);
// // export const getType = numDict => numDict.type;
export const getAdd = numDict => numDict.add;
export const getMul = numDict => numDict.mul;
// export const getAdd = numDict => numDict.add;
// export const getMul = numDict => numDict.mul;
// getAdd and getMul have same (generic) type:
const [getAddMulFnType, typesOfFns] = typedFnType2(fnType =>
makeGeneric(a => fnType({
in: numDictType(a),
out: fnType({
in: a,
out: fnType({in: a, out: a}),
}),
})));
// // const addOrMulIsConform = fn => {
// // // function signature must be: a -> a -> a
// // const i0 = fnIn(fn);
// // const o0 = fnOut(fn);
// // const i1 = fnIn(o0);
// // const o1 = fnOut(o0);
// // return deepEqual(i0, i1) && deepEqual(i1, o1);
// // };
export const ModuleNum = {l:[
...typedFnType(numDictType, fnType => fnType({in: Type, out: Type})),
{i: getAdd, t: getAddMulFnType},
{i: getMul, t: getAddMulFnType},
// // const addIsConform = {name: "isConform", inType: addType, outType: Bool, fn: addOrMulIsConform};
// // const mulIsConform = {name: "isConform", inType: mulType, outType: Bool, fn: addOrMulIsConform};
...typesOfFns,
]};
// export const ModuleNum = [
// {i: Num, t: Type},
// {i: NumDict, t: Type},
// {i: addType, t: Type},
// {i: addBoundType, t: Type},
// {i: mulType, t: Type},
// {i: mulBoundType, t: Type},
// {i: {name: "getType", inType: NumDict, outType: Num, fn: getType}, t: Function},
// {i: {name: "getAdd", inType: NumDict, outType: addType, fn: getAdd }, t: Function},
// {i: {name: "getMul", inType: NumDict, outType: mulType, fn: getMul }, t: Function},
// ...makeTypedFnInOut({f: addType , inType: Num, outType: addBoundType}),
// ...makeTypedFnInOut({f: addBoundType, inType: Num, outType: Num }),
// ...makeTypedFnInOut({f: mulType , inType: Num, outType: mulBoundType}),
// ...makeTypedFnInOut({f: mulBoundType, inType: Num, outType: Num }),
// // conformance checking type class
// {i: addType, t: Conformable},
// {i: mulType, t: Conformable},
// {i: addIsConform, t: Function},
// {i: addIsConform, t: conformanceCheck},
// {i: mulIsConform, t: Function},
// {i: mulIsConform, t: conformanceCheck},
// ];
const IntNumDict = {
add: addInt,
mul: mulInt,
};
const DoubleNumDict = {
add: addDouble,
mul: mulDouble,
}
export const ModuleNumInstances = {l:[
{i: IntNumDict , t: NumDict},
{i: DoubleNumDict, t: NumDict},
]};
// mapping from type to type class implementation
// in Haskell, such a mapping is global (for the entire application being compiled), and every type can implement every type class at most once.
// in Lean, such mappings can be local, and there can be multiple implementations per (type, type class).
// We have to follow Lean's approach, because in DOPE, there is no such thing as a "global scope". Every dependency is explicit, and type class resolution is just a function that always depends on a specific mapping:
export const NumInstances = new Map([
[Int , IntNumDict ],
[Double, DoubleNumDict],
]);