basic functionality, no generics
This commit is contained in:
commit
a8260f2afb
17 changed files with 615 additions and 0 deletions
15
function_registry.js
Normal file
15
function_registry.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { DefaultMap } from "./util.js";
|
||||||
|
|
||||||
|
const mapping = new DefaultMap(() => new Map());
|
||||||
|
|
||||||
|
export const getFnType = (inType, outType) => {
|
||||||
|
const m2 = mapping.getdefault(inType);
|
||||||
|
if (m2.has(outType)) {
|
||||||
|
return m2.get(outType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const fnType = {in: inType, out: outType};
|
||||||
|
m2.set(outType, fnType);
|
||||||
|
return fnType;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
lib/id.js
Normal file
38
lib/id.js
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import {Function} from "../metacircular.js";
|
||||||
|
|
||||||
|
// import {Typed} from "../typed.js";
|
||||||
|
|
||||||
|
// import {Bool} from "../primitives/symbols.js";
|
||||||
|
// import {deepEqual} from "../util.js";
|
||||||
|
// import {Conformable, conformanceCheck} from "../typeclasses/conformable.js";
|
||||||
|
|
||||||
|
// // Identity function
|
||||||
|
// const idBoundToType = Symbol('idBoundToType');
|
||||||
|
|
||||||
|
// const id = type => x => x;
|
||||||
|
// const idFn = {name: "id", inType: Type, outType: {inType: Type, outType: Type}, fn: id};
|
||||||
|
// const idIsConform = {
|
||||||
|
// name: "isConform",
|
||||||
|
// inType: idBoundToType,
|
||||||
|
// outType: Bool,
|
||||||
|
// fn: fn => deepEqual(fnIn(fn), fnOut(fn))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export const ModuleId = [
|
||||||
|
// {i: idBoundToType, t: Type},
|
||||||
|
// {i: idFn, t: Function},
|
||||||
|
// ... makeTypedFnInOut({f: idBoundToType, inType: Type, outType: Type}),
|
||||||
|
|
||||||
|
// {i: idBoundToType, t: Conformable},
|
||||||
|
// {i: idIsConform, t: conformanceCheck},
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// generates explicitly typed id-function
|
||||||
|
export const makeIdFn = typ => {
|
||||||
|
const Typ_to_Typ = {in: typ, out: typ};
|
||||||
|
const id = x => x;
|
||||||
|
return [
|
||||||
|
{i: id , t: Typ_to_Typ},
|
||||||
|
{i: Typ_to_Typ, t: Function},
|
||||||
|
];
|
||||||
|
};
|
||||||
30
lib/literals.js
Normal file
30
lib/literals.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import {Int, Bool, Double} from "../primitives/symbols.js";
|
||||||
|
import { getListType, makeListModule } from "../structures/list_common.js";
|
||||||
|
|
||||||
|
const ListOfBool = getListType(Bool);
|
||||||
|
const ListOfBoolModule = makeListModule(Bool);
|
||||||
|
|
||||||
|
const ListOfInt = getListType(Int);
|
||||||
|
const ListOfIntModule = makeListModule(Int);
|
||||||
|
|
||||||
|
const ListOfListOfInt = getListType(ListOfInt);
|
||||||
|
const ListOfListOfIntModule = makeListModule(ListOfInt);
|
||||||
|
|
||||||
|
export const ModuleLiterals = [
|
||||||
|
{i: 0n, t: Int},
|
||||||
|
{i: 42n, t: Int},
|
||||||
|
{i: false, t: Bool},
|
||||||
|
{i: 3.14159265359, t: Double},
|
||||||
|
|
||||||
|
{i: {l:[42n, 43n]}, t: ListOfInt},
|
||||||
|
|
||||||
|
// {i: [[42n, 43n]], t: ListOfListOfInt},
|
||||||
|
|
||||||
|
// i'm lazy
|
||||||
|
...ListOfIntModule,
|
||||||
|
|
||||||
|
|
||||||
|
// ...ListOfBoolModule,
|
||||||
|
|
||||||
|
// ...ListOfListOfIntModule,
|
||||||
|
];
|
||||||
49
lib/square.js
Normal file
49
lib/square.js
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import {Function, getIn, getOut} from "../metacircular.js";
|
||||||
|
import {Module} from "../structures/module.js";
|
||||||
|
import { deepEqual } from "../util.js";
|
||||||
|
import { Typed } from "../typed.js";
|
||||||
|
|
||||||
|
// import {Num, NumDict, getType, getMul} from "../typeclasses/num.js";
|
||||||
|
|
||||||
|
// const squareBoundToType = Symbol('squareBoundToType'); // the type of e.g., squareOfInt
|
||||||
|
|
||||||
|
// // returning a function + its signature is the only way to make the outType of square depend on its input
|
||||||
|
// const square = numDict => {
|
||||||
|
// const typ = getType(numDict);
|
||||||
|
// const mul = getMul(numDict);
|
||||||
|
// return {
|
||||||
|
// name: "squareOf:" + typ.toString(),
|
||||||
|
// inType: typ,
|
||||||
|
// outType: typ,
|
||||||
|
// fn: x => mul(x)(x),
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export const ModuleSquare = [
|
||||||
|
// {i: squareBoundToType, t: Type},
|
||||||
|
// {i: {name: "square", inType: NumDict, outType: squareBoundToType, fn: square}, t: Function},
|
||||||
|
// ...makeTypedFnInOut({f: squareBoundToType, inType: Num, outType: Num}),
|
||||||
|
// ];
|
||||||
|
|
||||||
|
|
||||||
|
export const makeSquare = ({i: mul, t: mulFunction}) => {
|
||||||
|
const numType = getIn(mulFunction);
|
||||||
|
const boundMulFunction = getOut(mulFunction);
|
||||||
|
if (!deepEqual(getOut(boundMulFunction), numType) || !deepEqual(getIn(boundMulFunction), numType)) {
|
||||||
|
console.log(getOut(boundMulFunction), getIn(boundMulFunction), numType);
|
||||||
|
throw new Error("invalid signature");
|
||||||
|
}
|
||||||
|
const square = x => mul(x)(x);
|
||||||
|
const squareFunction = {in: numType, out: numType};
|
||||||
|
return [
|
||||||
|
{i: square , t: squareFunction},
|
||||||
|
{i: squareFunction, t: Function},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeSquareType = {in: Typed, out: Module};
|
||||||
|
|
||||||
|
export const ModuleSquare = [
|
||||||
|
{i: makeSquare , t: makeSquareType},
|
||||||
|
{i: makeSquareType, t: Function},
|
||||||
|
];
|
||||||
170
main.js
Normal file
170
main.js
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
import {Function, ModuleMetaCircular, getIn, getOut} from "./metacircular.js";
|
||||||
|
import {ModuleTyped} from "./typed.js";
|
||||||
|
import {ModuleBool} from "./primitives/bool.js";
|
||||||
|
import { Double_to_Double_to_Double, ModuleDouble, mulDouble } from "./primitives/double.js";
|
||||||
|
import {Int_to_Int_to_Int, ModuleInt, mulInt} from "./primitives/int.js";
|
||||||
|
import {Int} from "./primitives/symbols.js";
|
||||||
|
import { makeSquare } from "./lib/square.js";
|
||||||
|
import {makeIdFn} from "./lib/id.js";
|
||||||
|
import {ModuleLiterals} from "./lib/literals.js";
|
||||||
|
|
||||||
|
import {DefaultMap} from "./util.js";
|
||||||
|
import { ModuleModule } from "./structures/module.js";
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
constructor(mod) {
|
||||||
|
// input type -> Function-signature
|
||||||
|
this.functionsFrom = new DefaultMap(() => []);
|
||||||
|
this.functionsTo = new DefaultMap(() => []);
|
||||||
|
this.types = new DefaultMap(() => []);
|
||||||
|
this.instances = new DefaultMap(() => []);
|
||||||
|
|
||||||
|
|
||||||
|
for (const {i, t} of mod) {
|
||||||
|
this.addInstance({i, t});
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(this.instances.m);
|
||||||
|
|
||||||
|
|
||||||
|
// const callEveryFunction = ({i,t}, indent=0) => {
|
||||||
|
// for (const fntype of this.functionsFrom.getdefault(t)) {
|
||||||
|
// for (const fn of this.instances.getdefault(fntype)) {
|
||||||
|
// console.log(" ", fn, ':', fntype);
|
||||||
|
// const result = fn(i);
|
||||||
|
// const resultType = getOut(fntype);
|
||||||
|
// console.log(" ".repeat(indent), i, '->', result);
|
||||||
|
// if (this.types.getdefault(resultType).includes(Function)) {
|
||||||
|
// if (indent < 2) {
|
||||||
|
// callEveryFunction({i: result, t: resultType}, indent+1)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const callFunction = (typ, fns) => {
|
||||||
|
// console.log("Functions callable on", typ, ":");
|
||||||
|
// for (const fn of fns) {
|
||||||
|
// console.log(" ", fn);
|
||||||
|
// for (const FN of this.instances.getdefault(fn)) {
|
||||||
|
// console.log(" ", FN);
|
||||||
|
// for (const i of this.instances.getdefault(typ)) {
|
||||||
|
// const result = FN(i);
|
||||||
|
// const resultType = getOut(fn);
|
||||||
|
// console.log(" ", i, '->', result);
|
||||||
|
// if (this.types.getdefault(resultType).includes(Function)) {
|
||||||
|
// callFunction(resultType, )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
const callFunctionOnEveryValue = (fn, fnType, indent=1) => {
|
||||||
|
const inType = getIn(fnType);
|
||||||
|
const outType = getOut(fnType);
|
||||||
|
console.log("--".repeat(indent), fn, ':', fnType);
|
||||||
|
for (const i of this.instances.getdefault(inType)) {
|
||||||
|
const result = fn(i);
|
||||||
|
console.log("--".repeat(indent+1), i, '->', result);
|
||||||
|
if (this.types.getdefault(outType).includes(Function)) {
|
||||||
|
if (indent < 5) {
|
||||||
|
callFunctionOnEveryValue(result, outType, indent+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const fntypes of this.functionsFrom.m.values()) {
|
||||||
|
for (const fntype of fntypes) {
|
||||||
|
for (const fn of this.instances.getdefault(fntype)) {
|
||||||
|
callFunctionOnEveryValue(fn, fntype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (const [i, ts] of this.types.m.entries()) {
|
||||||
|
// for (const t of ts) {
|
||||||
|
// callEveryFunction({i,t});
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// // Conformance check
|
||||||
|
// for (const fn of this.instances.getdefault(conformanceCheck)) {
|
||||||
|
// const t = fn.inType;
|
||||||
|
// for (const i of this.instances.getdefault(t)) {
|
||||||
|
// if (!fn.fn(i)) {
|
||||||
|
// console.warn(i, 'is not conform', 'to', t);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// console.info('👍', i, 'conforms to', t);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const MAXDEPTH = 0;
|
||||||
|
|
||||||
|
// let calls = 0;
|
||||||
|
// const tryEveryFunction = ({i, t}, maxDepth) => {
|
||||||
|
// calls++;
|
||||||
|
// for (const fn of this.functionsFrom.getdefault(t)) {
|
||||||
|
// const outType = getOut(fn);
|
||||||
|
// // console.log(" ".repeat(MAXDEPTH-maxDepth) + 'calling', fn, 'on', i);
|
||||||
|
// const result = fn(i);
|
||||||
|
// console.log(" ".repeat(MAXDEPTH-maxDepth), result, 'should be of type', outType);
|
||||||
|
// if (outType === TypeLink && result.t === undefined) {
|
||||||
|
// console.warn(" ".repeat(MAXDEPTH-maxDepth) + ' ^ invalid')
|
||||||
|
// }
|
||||||
|
// if (outType === Int && (typeof result) !== "number") {
|
||||||
|
// console.warn(" ".repeat(MAXDEPTH-maxDepth) + ' ^ invalid')
|
||||||
|
// }
|
||||||
|
// this.addInstance({i: result, t: outType});
|
||||||
|
// if (maxDepth > 0) {
|
||||||
|
// tryEveryFunction({i: result, t: outType}, maxDepth-1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (const {i, t} of mod) {
|
||||||
|
// tryEveryFunction({i, t}, MAXDEPTH);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// console.log("calls:", calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
addInstance({i, t}) {
|
||||||
|
const arr = this.types.getdefault(i, true);
|
||||||
|
arr.push(t);
|
||||||
|
const arrI = this.instances.getdefault(t, true);
|
||||||
|
arrI.push(i);
|
||||||
|
if (t === Function) {
|
||||||
|
const arr = this.functionsFrom.getdefault(getIn(i), true);
|
||||||
|
arr.push(i);
|
||||||
|
const arrTo = this.functionsTo.getdefault(getOut(i), true);
|
||||||
|
arrTo.push(i);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ctx = new Context([
|
||||||
|
...ModuleMetaCircular,
|
||||||
|
...ModuleTyped,
|
||||||
|
// ...ModuleConformable,
|
||||||
|
// ...ModuleConformanceCheckConforms,
|
||||||
|
// ...ModuleNum,
|
||||||
|
// ...ModuleEq,
|
||||||
|
...ModuleBool,
|
||||||
|
...ModuleInt,
|
||||||
|
...ModuleDouble,
|
||||||
|
// ...ModuleSquare,
|
||||||
|
// ...ModuleList,
|
||||||
|
...makeIdFn(Int),
|
||||||
|
...makeSquare({i: mulInt, t: Int_to_Int_to_Int}),
|
||||||
|
...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}),
|
||||||
|
...ModuleLiterals,
|
||||||
|
...ModuleModule,
|
||||||
|
]);
|
||||||
31
metacircular.js
Normal file
31
metacircular.js
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { getFnType } from "./function_registry.js";
|
||||||
|
|
||||||
|
export const Type = Symbol('Type');
|
||||||
|
export const Function = Symbol('Function');
|
||||||
|
|
||||||
|
// Implementation of 'in' and 'out' functions,
|
||||||
|
// to get input/output type of a function signature:
|
||||||
|
export const getIn = fn => fn.in;
|
||||||
|
export const getOut = fn => fn.out;
|
||||||
|
|
||||||
|
// a module is just a set of typed objects
|
||||||
|
// each 'typed object' is implicitly an instance of TypeLink (defined below)
|
||||||
|
export const ModuleMetaCircular = [
|
||||||
|
// TODO? maybe follow Lean so
|
||||||
|
// Type.{0} : Type.{1}
|
||||||
|
// Type.{1} : Type.{2}
|
||||||
|
// ...
|
||||||
|
// see: https://lean-lang.org/functional_programming_in_lean/functor-applicative-monad/universes.html
|
||||||
|
|
||||||
|
// Type : Type
|
||||||
|
{i: Type, t: Type},
|
||||||
|
|
||||||
|
// Function : Type
|
||||||
|
{i: Function, t: Type},
|
||||||
|
|
||||||
|
// (Function -> Type) : Function
|
||||||
|
{i: getFnType(Function, Type), t: Function},
|
||||||
|
|
||||||
|
{i: getIn , t: getFnType(Function, Type)},
|
||||||
|
{i: getOut, t: getFnType(Function, Type)},
|
||||||
|
];
|
||||||
14
primitives/bool.js
Normal file
14
primitives/bool.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
import {Bool} from "./symbols.js";
|
||||||
|
|
||||||
|
const eqBool = x => y => x === y;
|
||||||
|
|
||||||
|
const Bool_to_Bool = {in: Bool, out: Bool};
|
||||||
|
const Bool_to_Bool_to_Bool = {in: Bool, out: Bool_to_Bool};
|
||||||
|
|
||||||
|
export const ModuleBool = [
|
||||||
|
{i: Bool , t: Type },
|
||||||
|
{i: Bool_to_Bool , t: Function },
|
||||||
|
{i: Bool_to_Bool_to_Bool , t: Function },
|
||||||
|
{i: eqBool , t: Bool_to_Bool_to_Bool },
|
||||||
|
];
|
||||||
26
primitives/double.js
Normal file
26
primitives/double.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
|
||||||
|
import {Bool, Double} from "./symbols.js";
|
||||||
|
|
||||||
|
export const addDouble = x => y => x + y;
|
||||||
|
export const mulDouble = x => y => x * y;
|
||||||
|
export const eqDouble = x => y => x === y;
|
||||||
|
|
||||||
|
const Double_to_Double = {in: Double, out: Double};
|
||||||
|
const Double_to_Bool = {in: Double, out: Bool};
|
||||||
|
export const Double_to_Double_to_Double = {in: Double, out: Double_to_Double};
|
||||||
|
export const Double_to_Double_to_Bool = {in: Double, out: Double_to_Bool};
|
||||||
|
|
||||||
|
|
||||||
|
export const ModuleDouble = [
|
||||||
|
{i: Double , t: Type },
|
||||||
|
|
||||||
|
{i: Double_to_Double_to_Double, t: Function },
|
||||||
|
{i: Double_to_Double_to_Bool , t: Function },
|
||||||
|
{i: Double_to_Double , t: Function },
|
||||||
|
{i: Double_to_Bool , t: Function },
|
||||||
|
|
||||||
|
{i: addDouble , t: Double_to_Double_to_Double },
|
||||||
|
{i: mulDouble , t: Double_to_Double_to_Double },
|
||||||
|
{i: eqDouble , t: Double_to_Double_to_Bool },
|
||||||
|
];
|
||||||
26
primitives/int.js
Normal file
26
primitives/int.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
|
||||||
|
import {Bool, Int} from "./symbols.js";
|
||||||
|
|
||||||
|
export const addInt = x => y => x + y;
|
||||||
|
export const mulInt = x => y => x * y;
|
||||||
|
export const eqInt = x => y => x === y;
|
||||||
|
|
||||||
|
const Int_to_Int = {in: Int, out: Int };
|
||||||
|
const Int_to_Bool = {in: Int, out: Bool};
|
||||||
|
export const Int_to_Int_to_Int = {in: Int, out: Int_to_Int};
|
||||||
|
export const Int_to_Int_to_Bool = {in: Int, out: Int_to_Bool};
|
||||||
|
|
||||||
|
|
||||||
|
export const ModuleInt = [
|
||||||
|
{i: Int , t: Type },
|
||||||
|
|
||||||
|
{i: Int_to_Int_to_Int , t: Function },
|
||||||
|
{i: Int_to_Int_to_Bool , t: Function },
|
||||||
|
{i: Int_to_Int , t: Function },
|
||||||
|
{i: Int_to_Bool , t: Function },
|
||||||
|
|
||||||
|
{i: addInt , t: Int_to_Int_to_Int },
|
||||||
|
{i: mulInt , t: Int_to_Int_to_Int },
|
||||||
|
{i: eqInt , t: Int_to_Int_to_Bool },
|
||||||
|
];
|
||||||
5
primitives/symbols.js
Normal file
5
primitives/symbols.js
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
// to break up dependency cycles, symbols of primitive types have their own JS module
|
||||||
|
|
||||||
|
export const Bool = Symbol('Bool');
|
||||||
|
export const Int = Symbol('Int');
|
||||||
|
export const Double = Symbol('Double');
|
||||||
13
structures/list.js
Normal file
13
structures/list.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
import { makeListModule } from "./list_common.js";
|
||||||
|
|
||||||
|
const Type_to_Type = {in: Type, out: Type};
|
||||||
|
const Type_to_Module = {in: Type, out: Module};
|
||||||
|
|
||||||
|
export const ModuleList = [
|
||||||
|
{i: getListType , t: Type_to_Type},
|
||||||
|
{i: Type_to_Type , t: Function},
|
||||||
|
|
||||||
|
{i: makeListModule, t: Type_to_Module},
|
||||||
|
{i: Type_to_Module, t: Function},
|
||||||
|
];
|
||||||
46
structures/list_common.js
Normal file
46
structures/list_common.js
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import {Type, Function} from "../metacircular.js";
|
||||||
|
import {Int} from "../primitives/symbols.js";
|
||||||
|
|
||||||
|
// Global store of list types:
|
||||||
|
const listTypes = new Map();
|
||||||
|
export function getListType(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 = Symbol('ListOf:'+elementType.toString());
|
||||||
|
listTypes.set(elementType, type);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeListModule = elementType => {
|
||||||
|
// List<elementType> type depends on elementType
|
||||||
|
// generating it another time, will give the same type (structurally equivalent):
|
||||||
|
const ListOfElement = getListType(elementType);
|
||||||
|
|
||||||
|
const emptyList = {l:[]};
|
||||||
|
|
||||||
|
const get = ls => i => ls.l[i];
|
||||||
|
const getBoundType = {in: Int, out: elementType}
|
||||||
|
const getType = {in: ListOfElement, out: getBoundType};
|
||||||
|
|
||||||
|
const push = ls => elem => ({l:ls.l.concat([elem])});
|
||||||
|
const pushBoundType = {in: elementType, out: ListOfElement};
|
||||||
|
const pushType = {in: ListOfElement, out: pushBoundType};
|
||||||
|
|
||||||
|
return [
|
||||||
|
{i: ListOfElement, t: Type},
|
||||||
|
{i: emptyList , t: ListOfElement},
|
||||||
|
|
||||||
|
{i: get , t: getType},
|
||||||
|
{i: getType , t: Function},
|
||||||
|
{i: getBoundType , t: Function},
|
||||||
|
|
||||||
|
{i: push , t: pushType},
|
||||||
|
{i: pushType , t: Function},
|
||||||
|
{i: pushBoundType, t: Function},
|
||||||
|
];
|
||||||
|
};
|
||||||
6
structures/module.js
Normal file
6
structures/module.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { getListType, makeListModule } from "./list_common.js";
|
||||||
|
import { Typed } from "../typed.js";
|
||||||
|
|
||||||
|
export const Module = getListType(Typed); // a Module is a list of Typeds
|
||||||
|
|
||||||
|
export const ModuleModule = makeListModule(Typed); // the module containing operations on Module
|
||||||
33
typeclasses/conformable.js
Normal file
33
typeclasses/conformable.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// 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},
|
||||||
|
// ];
|
||||||
52
typeclasses/num.js
Normal file
52
typeclasses/num.js
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
|
||||||
|
// // export const getType = numDict => numDict.type;
|
||||||
|
|
||||||
|
// export const getAdd = numDict => numDict.add;
|
||||||
|
// export const getMul = numDict => numDict.mul;
|
||||||
|
|
||||||
|
// // 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);
|
||||||
|
// // };
|
||||||
|
|
||||||
|
// // const addIsConform = {name: "isConform", inType: addType, outType: Bool, fn: addOrMulIsConform};
|
||||||
|
// // const mulIsConform = {name: "isConform", inType: mulType, outType: Bool, fn: addOrMulIsConform};
|
||||||
|
|
||||||
|
// 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},
|
||||||
|
// ];
|
||||||
19
typed.js
Normal file
19
typed.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { getFnType } from "./function_registry.js";
|
||||||
|
import {Type, Function} from "./metacircular.js";
|
||||||
|
|
||||||
|
export const Typed = Symbol('Typed');
|
||||||
|
|
||||||
|
const getInst = lnk => lnk.i;
|
||||||
|
const getType = lnk => lnk.t;
|
||||||
|
|
||||||
|
// const Typed_to_Type = {in: Typed, out: Type};
|
||||||
|
const Typed_to_Type = getFnType(Typed, Type);
|
||||||
|
|
||||||
|
export const ModuleTyped = [
|
||||||
|
{i: Typed, t: Type},
|
||||||
|
|
||||||
|
{i: Typed_to_Type, t: Function},
|
||||||
|
|
||||||
|
{i: getInst, t: Typed_to_Type},
|
||||||
|
{i: getType, t: Typed_to_Type},
|
||||||
|
];
|
||||||
42
util.js
Normal file
42
util.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
// re-inventing the wheel:
|
||||||
|
export function deepEqual(a, b) {
|
||||||
|
if (a === b) return true; // <- shallow equality and primitives
|
||||||
|
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Array.isArray(a) && Array.isArray(b)) {
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (!deepEqual(a[i], b[i])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const keysA = Object.keys(a);
|
||||||
|
const keysB = Object.keys(b);
|
||||||
|
if (keysA.length !== keysB.length) return false;
|
||||||
|
for (let key of keysA) {
|
||||||
|
if (!keysB.includes(key) || !deepEqual(a[key], b[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class DefaultMap {
|
||||||
|
constructor(defaultValue, ...rest) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
this.m = new Map(rest);
|
||||||
|
}
|
||||||
|
getdefault(key, addToMapping=false) {
|
||||||
|
return this.m.get(key) || (() => {
|
||||||
|
const val = this.defaultValue();
|
||||||
|
if (addToMapping)
|
||||||
|
this.m.set(key, val);
|
||||||
|
return val;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
entries() {
|
||||||
|
return this.m.entries();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue