lotta progress
This commit is contained in:
parent
29d20b2273
commit
bc91d9bf39
27 changed files with 317 additions and 475 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { eqType } from "../metacircular.js";
|
||||
import { eqType } from "../type.js";
|
||||
import { pretty, zip } from "../util.js";
|
||||
|
||||
// constructor for generic types
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Bool, Int } from "../primitives/symbols.js";
|
||||
import { lsType } from "../structures/list.js";
|
||||
import { Bool, Int } from "../primitives/types.js";
|
||||
import { lsType } from "../structures/types.js";
|
||||
import { fnType } from "../structures/function.js";
|
||||
import { assign, makeGeneric, unify } from "./generics.js";
|
||||
import { pretty } from "../util.js";
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
import { fnType, lsType } from "../type_registry.js";
|
||||
import {Type, Function} from "../metacircular.js";
|
||||
import { Byte } from "../primitives/symbols.js";
|
||||
|
||||
export const Serializable = Symbol('Serializable');
|
||||
|
||||
const ListOfByte = lsType(Byte);
|
||||
|
||||
const serializeFnType = fnType({in: Serializable, out: ListOfByte});
|
||||
const deserializeFnType = fnType({in: ListOfByte, out: Serializable});
|
||||
|
||||
export const ModuleSerializable = {l:[
|
||||
{i: Serializable , t: Type},
|
||||
{i: serializeFnType , t: Function},
|
||||
{i: deserializeFnType, t: Function},
|
||||
]};
|
||||
39
lib/id.js
39
lib/id.js
|
|
@ -1,39 +0,0 @@
|
|||
// import { fnType } from "../metacircular.js";
|
||||
// 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 = fnType({in: typ, out: typ});
|
||||
// const id = x => x;
|
||||
// return {l:[
|
||||
// {i: id , t: Typ_to_Typ},
|
||||
// {i: Typ_to_Typ, t: Function},
|
||||
// ]};
|
||||
// };
|
||||
79
lib/point.js
79
lib/point.js
|
|
@ -1,65 +1,72 @@
|
|||
import { Double } from "../primitives/symbols.js";
|
||||
import { nominalType, NominalType } from "../structures/nominal_type.js";
|
||||
import { makeProductType } from "../structures/product.js";
|
||||
import { typedFnType } from "../metacircular.js";
|
||||
import { prodType } from "../structures/product.js";
|
||||
import { Type } from "../type.js";
|
||||
import { typedFnType } from "../structures/types.js"
|
||||
import { Double } from "../primitives/types.js";
|
||||
|
||||
const PointCartesian2D = nominalType(
|
||||
"PointCartesian2D")
|
||||
// just a unique number, to make sure that our type is only equal to itself
|
||||
// BigInt("0xBBAAD62B10EE21993BA690A732DA2A6875CE4B6F5E7139D5AEC9FD887F9D24A8"))
|
||||
(prodType(Double, Double));
|
||||
// Create nominal types
|
||||
export const PointCartesian2D = { symbol: Symbol('PointCartesian2D'), params: [] };
|
||||
export const PointPolar2D = { symbol: Symbol('PointPolar2D') , params: [] };
|
||||
|
||||
const PointPolar2D = nominalType(
|
||||
"PointPolar2D")
|
||||
// just a unique number, to make sure that our type is only equal to itself
|
||||
// BigInt("0x31CDAB4B3D84C4EB27D3C111FD7580E533268B72E05BD694F8B262913E018B72"))
|
||||
(prodType(Double, Double));
|
||||
|
||||
export const cart2polar = ({left: x, right: y}) => {
|
||||
export const cart2polar = ({x, y}) => {
|
||||
const r = Math.sqrt(x*x + y*y);
|
||||
const θ = Math.atan(y/x);
|
||||
return {left: r, right: θ};
|
||||
return {r, θ};
|
||||
};
|
||||
|
||||
export const polar2cart = ({left: r, right: θ}) => {
|
||||
export const polar2cart = ({r, θ}) => {
|
||||
const x = r * Math.cos(θ);
|
||||
const y = r * Math.sin(θ);
|
||||
return {left: x, right: y};
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
export const translate = dx => dy => ({left: x, right: y}) => {
|
||||
export const translate = dx => dy => ({x, y}) => {
|
||||
return {left: x+dx, right: y+dy};
|
||||
}
|
||||
|
||||
export const rotate = dθ => ({left: r, right: θ}) => {
|
||||
return {left: r, right: θ+dθ};
|
||||
export const rotate = dθ => ({r, θ}) => {
|
||||
return {r, θ: θ+dθ};
|
||||
}
|
||||
|
||||
export const scale = dr => ({left: r, right: θ}) => {
|
||||
return {left: r+dr, right: θ};
|
||||
export const scale = dr => ({r, θ}) => {
|
||||
return {r: r+dr, θ};
|
||||
}
|
||||
|
||||
const examplePoint = {left: 1, right: 2};
|
||||
const examplePoint = {x: 1, y: 2};
|
||||
|
||||
export const ModulePoint = {l:[
|
||||
{i: -1 , t: Double},
|
||||
{i: 2 , t: Double},
|
||||
{i: examplePoint , t: PointCartesian2D},
|
||||
{i: examplePoint , t: prodType(Double, Double)},
|
||||
|
||||
...makeProductType(Double, Double).l,
|
||||
{i: PointCartesian2D , t: Type},
|
||||
{i: PointPolar2D , t: Type},
|
||||
|
||||
{i: PointCartesian2D , t: NominalType},
|
||||
{i: PointPolar2D , t: NominalType},
|
||||
...typedFnType(cart2polar, fnType => fnType(PointCartesian2D)(PointPolar2D)),
|
||||
|
||||
...typedFnType(cart2polar, fnType => fnType({in: PointCartesian2D, out: PointPolar2D})),
|
||||
...typedFnType(polar2cart, fnType => fnType(PointPolar2D)(PointCartesian2D)),
|
||||
|
||||
...typedFnType(polar2cart, fnType => fnType({in: PointPolar2D, out: PointCartesian2D})),
|
||||
// Double -> Double -> PointCartesian2D -> PointCartesian2D
|
||||
...typedFnType(translate, fnType =>
|
||||
fnType
|
||||
(Double)
|
||||
(fnType
|
||||
(Double)
|
||||
(fnType
|
||||
(PointCartesian2D)
|
||||
(PointCartesian2D)))),
|
||||
|
||||
...typedFnType(translate , fnType => fnType({in: Double, out: fnType({in: Double, out: fnType({in: PointCartesian2D, out: PointCartesian2D})})})),
|
||||
// Double -> PointPolar2D -> PointPolar2D
|
||||
...typedFnType(rotate, fnType =>
|
||||
fnType
|
||||
(Double)
|
||||
(fnType
|
||||
(PointPolar2D)
|
||||
(PointPolar2D))),
|
||||
|
||||
...typedFnType(rotate, fnType => fnType({in: Double, out: fnType({in: PointPolar2D, out: PointPolar2D})})),
|
||||
|
||||
...typedFnType(scale, fnType => fnType({in: Double, out: fnType({in: PointPolar2D, out: PointPolar2D})})),
|
||||
// Double -> PointPolar2D -> PointPolar2D
|
||||
...typedFnType(scale, fnType =>
|
||||
fnType
|
||||
(Double)
|
||||
(fnType
|
||||
(PointPolar2D)
|
||||
(PointPolar2D))),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
// import { getIn, getOut } from "../metacircular.js";
|
||||
// import {Module} from "../structures/list_types/module.js";
|
||||
// import { deepEqual } from "../util.js";
|
||||
// import { Typed } from "../typed.js";
|
||||
// import { fnType } from "../metacircular.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 = fnType({in: numType, out: numType});
|
||||
// return {l:[
|
||||
// {i: square , t: squareFunction},
|
||||
// {i: squareFunction, t: Function},
|
||||
// ]};
|
||||
// };
|
||||
|
||||
// const makeSquareType = fnType({in: Typed, out: Module});
|
||||
|
||||
// export const ModuleSquare = {l:[
|
||||
// {i: makeSquare , t: makeSquareType},
|
||||
// {i: makeSquareType, t: Function},
|
||||
// ]};
|
||||
98
main.js
98
main.js
|
|
@ -1,38 +1,28 @@
|
|||
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 { makeSquare } from "./lib/square.js";
|
||||
import {makeIdFn} from "./lib/id.js";
|
||||
|
||||
import {DefaultMap, pretty} from "./util.js";
|
||||
import { ModuleModule } from "./structures/list_types/module.js";
|
||||
import { ModuleList } from "./structures/list.js";
|
||||
import {Int, Bool, Double, Byte} from "./primitives/symbols.js";
|
||||
import { makeListModule } from "./structures/list_common.js";
|
||||
import { makeProductType } from "./structures/product.js";
|
||||
import { makeSumType } from "./structures/sum.js";
|
||||
import { sumType } from "./structures/sum.js";
|
||||
import { prodType } from "./structures/product.js";
|
||||
import { lsType } from "./structures/list_common.js";
|
||||
import { select } from '@inquirer/prompts';
|
||||
import { ModulePoint } from "./lib/point.js";
|
||||
import { DefaultMap, pretty } from './util.js';
|
||||
import { symbolFunction } from './structures/types.js';
|
||||
import { ModuleStd } from './stdlib.js';
|
||||
|
||||
class Context {
|
||||
constructor(mod) {
|
||||
this.functionsFrom = new DefaultMap(() => []);
|
||||
this.functionsTo = new DefaultMap(() => []);
|
||||
this.types = new DefaultMap(() => []);
|
||||
this.instances = new DefaultMap(() => []);
|
||||
this.functionsFrom = new DefaultMap(() => []); // type to outgoing function
|
||||
this.functionsTo = new DefaultMap(() => []); // type to incoming function
|
||||
this.types = new DefaultMap(() => []); // instance to type
|
||||
this.instances = new DefaultMap(() => []); // type to instance
|
||||
|
||||
for (const {i, t} of mod.l) {
|
||||
this.types.getdefault(i, true).push(t);
|
||||
this.instances.getdefault(t, true).push(i);
|
||||
}
|
||||
|
||||
for (const fnType of this.instances.getdefault(Function)) {
|
||||
for (const fn of this.instances.getdefault(fnType)) {
|
||||
this.functionsFrom.getdefault(getIn(fnType), true).push(fn);
|
||||
this.functionsTo.getdefault(getOut(fnType), true).push(fn);
|
||||
for (const [i, types] of this.instances.m.entries()) {
|
||||
for (const t of types) {
|
||||
if (t.symbol === symbolFunction) {
|
||||
// 'i' is a function
|
||||
this.functionsFrom.getdefault(t.params[0], true).push(i);
|
||||
this.functionsFrom.getdefault(t.params[1], true).push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -68,62 +58,8 @@ class Context {
|
|||
// }
|
||||
}
|
||||
|
||||
const ListOfDouble = lsType(Double);
|
||||
const ListOfDoubleModule = makeListModule(Double);
|
||||
|
||||
const ListOfListOfDouble = lsType(ListOfDouble);
|
||||
const ListOfListOfDoubleModule = makeListModule(ListOfDouble);
|
||||
|
||||
const ListOfByte = lsType(Byte);
|
||||
const ListOfByteModule = makeListModule(Byte);
|
||||
|
||||
const ModuleValues = {l:[
|
||||
{i: 0n, t: Int},
|
||||
{i: 42n, t: Int},
|
||||
{i: false, t: Bool},
|
||||
{i: 3.14159265359, t: Double},
|
||||
|
||||
{i: {l:[4.2, 7.6]} , t: ListOfDouble},
|
||||
{i: {l:[{l:[4.2, 7.6]}, {l:[4.3]}]}, t: ListOfListOfDouble},
|
||||
|
||||
{i: new Uint8Array([1,2,3]), t: ListOfByte},
|
||||
|
||||
// i'm lazy
|
||||
...ListOfDoubleModule.l,
|
||||
...ListOfListOfDoubleModule.l,
|
||||
...ListOfByteModule.l,
|
||||
|
||||
|
||||
...makeProductType(Int, Bool).l,
|
||||
|
||||
...makeSumType(Int, Bool).l,
|
||||
|
||||
{i: {left: 42n, right: true}, t: prodType(Int, Bool)},
|
||||
{i: {variant: "L", value: 100n}, t: sumType(Int, Bool)},
|
||||
]};
|
||||
|
||||
import { select } from '@inquirer/prompts';
|
||||
import { ModulePoint } from "./lib/point.js";
|
||||
|
||||
|
||||
const ctx = new Context({l:[
|
||||
// ...ModuleMetaCircular.l,
|
||||
// ...ModuleTyped.l,
|
||||
// // ...ModuleConformable,
|
||||
// // ...ModuleConformanceCheckConforms,
|
||||
// // ...ModuleNum,
|
||||
// // ...ModuleEq,
|
||||
// ...ModuleBool.l,
|
||||
// ...ModuleInt.l,
|
||||
// ...ModuleDouble.l,
|
||||
// // ...ModuleSquare,
|
||||
// // ...ModuleList,
|
||||
// ...makeIdFn(Int).l,
|
||||
// ...makeSquare({i: mulInt, t: Int_to_Int_to_Int}).l,
|
||||
// ...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}).l,
|
||||
// ...ModuleList.l,
|
||||
// ...ModuleValues.l,
|
||||
// ...ModuleModule.l,
|
||||
...ModuleStd.l,
|
||||
...ModulePoint.l,
|
||||
]});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import { fnType } from "../structures/function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { Bool } from "./symbols.js";
|
||||
import { fnType, typedFnType } from "../structures/types.js";
|
||||
import { Type } from "../type.js";
|
||||
import { Bool } from "./types.js";
|
||||
|
||||
const eqBool = x => y => x === y;
|
||||
|
||||
const Bool_to_Bool = fnType({in: Bool, out: Bool});
|
||||
const Bool_to_Bool_to_Bool = fnType({in: Bool, out: Bool_to_Bool});
|
||||
|
||||
export const ModuleBool = {l:[
|
||||
{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 },
|
||||
{i: true , t: Bool},
|
||||
{i: false, t: Bool},
|
||||
|
||||
{i: Bool , t: Type},
|
||||
|
||||
// Bool -> Bool -> Bool
|
||||
...typedFnType(eqBool, fnType => fnType(Bool)(fnType(Bool)(Bool))),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
import { fnType } from "../structures/function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import {Byte, Bool} from "./symbols.js";
|
||||
import { typedFnType } from "../structures/types.js";
|
||||
import { Type } from "../type.js";
|
||||
import {Byte, Bool} from "./types.js";
|
||||
|
||||
const eqByte = x => y => x === y;
|
||||
|
||||
const Byte_to_Bool = fnType({in: Byte, out: Bool});
|
||||
const Byte_to_Byte_to_Bool = fnType({in: Byte, out: Byte_to_Bool});
|
||||
|
||||
export const ModuleByte = {l:[
|
||||
{i: Byte , t: Type },
|
||||
{i: Byte_to_Bool , t: Function },
|
||||
{i: Byte_to_Byte_to_Bool , t: Function },
|
||||
{i: eqByte , t: Byte_to_Byte_to_Bool },
|
||||
|
||||
...typedFnType(eqByte, fnType => fnType(Byte)(fnType(Byte)(Bool))),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { typedFnType } from "../structures/function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import {Char, Bool} from "./symbols.js";
|
||||
import { typedFnType } from "../structures/types.js";
|
||||
import { Type } from "../type.js";
|
||||
import {Char, Bool} from "./types.js";
|
||||
|
||||
const eq = x => y => x === y;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,15 @@
|
|||
import { fnType } from "../structures/function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import {Bool, Double} from "./symbols.js";
|
||||
import { typedFnType } from "../structures/types.js";
|
||||
import { Type } from "../type.js";
|
||||
import {Bool, Double} from "./types.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 = fnType({in: Double, out: Double});
|
||||
const Double_to_Bool = fnType({in: Double, out: Bool});
|
||||
export const Double_to_Double_to_Double = fnType({in: Double, out: Double_to_Double});
|
||||
export const Double_to_Double_to_Bool = fnType({in: Double, out: Double_to_Bool});
|
||||
|
||||
|
||||
export const ModuleDouble = {l:[
|
||||
{i: Double , t: Type },
|
||||
{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 },
|
||||
...typedFnType(addDouble, fnType => fnType(Double)(fnType(Double)(Double))),
|
||||
...typedFnType(mulDouble, fnType => fnType(Double)(fnType(Double)(Double))),
|
||||
...typedFnType(eqDouble, fnType => fnType(Double)(fnType(Double)(Bool))),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,30 +1,19 @@
|
|||
import { fnType } from "../structures/function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { typedFnType } from "../structures/types.js";
|
||||
import { Type } from "../type.js";
|
||||
|
||||
import {Bool, Int} from "./symbols.js";
|
||||
import {Bool, Int} from "./types.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 = fnType({in: Int, out: Int });
|
||||
const Int_to_Bool = fnType({in: Int, out: Bool});
|
||||
export const Int_to_Int_to_Int = fnType({in: Int, out: Int_to_Int});
|
||||
export const Int_to_Int_to_Bool = fnType({in: Int, out: Int_to_Bool});
|
||||
|
||||
const serialize = x => x.toString();
|
||||
const deserialize = str => BigInt(str);
|
||||
|
||||
|
||||
export const ModuleInt = {l:[
|
||||
{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 },
|
||||
...typedFnType(addInt, fnType => fnType(Int)(fnType(Int)(Int))),
|
||||
...typedFnType(mulInt, fnType => fnType(Int)(fnType(Int)(Int))),
|
||||
...typedFnType(eqInt , fnType => fnType(Int)(fnType(Int)(Bool))),
|
||||
]};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// to break up dependency cycles, primitive types are defined in their own JS module
|
||||
|
||||
|
||||
export const Int = { symbol: Symbol('Int') , params: [] };
|
||||
export const Bool = { symbol: Symbol('Bool') , params: [] };
|
||||
export const Double = { symbol: Symbol('Double'), params: [] };
|
||||
export const Byte = { symbol: Symbol('Byte') , params: [] };
|
||||
export const Char = { symbol: Symbol('Char') , params: [] };
|
||||
export const Char = { symbol: Symbol('Char') , params: [] };// Wrapper around function below.
|
||||
29
stdlib.js
Normal file
29
stdlib.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { ModuleBool } from "./primitives/bool.js";
|
||||
import { ModuleByte } from "./primitives/byte.js";
|
||||
import { ModuleChar } from "./primitives/char.js";
|
||||
import { ModuleDouble } from "./primitives/double.js";
|
||||
import { ModuleInt } from "./primitives/int.js";
|
||||
import { ModuleFunction } from "./structures/function.js";
|
||||
import { ModuleList } from "./structures/list.js";
|
||||
import { ModuleProduct } from "./structures/product.js";
|
||||
import { ModuleSum } from "./structures/sum.js";
|
||||
import { ModuleType } from "./type.js";
|
||||
import { ModuleTyped } from "./typed.js";
|
||||
|
||||
export const ModuleStd = {l:[
|
||||
...ModuleType.l,
|
||||
...ModuleTyped.l,
|
||||
|
||||
// Primitive types
|
||||
...ModuleBool.l,
|
||||
...ModuleByte.l,
|
||||
...ModuleChar.l,
|
||||
...ModuleDouble.l,
|
||||
...ModuleInt.l,
|
||||
|
||||
// Types that consist of other types
|
||||
...ModuleFunction.l,
|
||||
...ModuleList.l,
|
||||
...ModuleProduct.l,
|
||||
...ModuleSum.l,
|
||||
]};
|
||||
|
|
@ -1,42 +1,6 @@
|
|||
import { DefaultMap } from "../util.js";
|
||||
|
||||
const symbolFunction = Symbol('Function');
|
||||
|
||||
// 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, ...)
|
||||
const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({
|
||||
symbol: symbolFunction,
|
||||
params: [inType, outType],
|
||||
})));
|
||||
|
||||
// type constructor for function types
|
||||
export const fnType = inType => outType => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true);
|
||||
|
||||
|
||||
// Wrapper around function below.
|
||||
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 wrappedFnType = ({ in: inType, out: outType }) => {
|
||||
const fnT = fnType({ in: inType, out: outType });
|
||||
fnTs.push(fnT);
|
||||
return fnT;
|
||||
};
|
||||
const t = callback(wrappedFnType); // force evaluation
|
||||
return [
|
||||
t,
|
||||
fnTs.map(fnT => ({ i: fnT, t: Function })),
|
||||
];
|
||||
};
|
||||
import { Type } from "../type.js";
|
||||
import { typedFnType } from "./types.js";
|
||||
import { fnType } from "./types.js";
|
||||
|
||||
|
||||
export const ModuleFunction = {l:[
|
||||
|
|
|
|||
|
|
@ -1,18 +1,8 @@
|
|||
import { typedFnType } from "./function.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { Int } from "../primitives/symbols.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
import { typedFnType } from "./types.js";
|
||||
import { Type } from "../type.js";
|
||||
import { Int } from "../primitives/types.js";
|
||||
import { makeGeneric } from "../generics/generics.js";
|
||||
|
||||
const symbolList = Symbol('List');
|
||||
|
||||
const listTypeRegistry = new DefaultMap(elementType => ({
|
||||
symbol: symbolList,
|
||||
params: [elementType],
|
||||
}));
|
||||
|
||||
// type constructor
|
||||
export const lsType = elementType => listTypeRegistry.getdefault(elementType, true);
|
||||
import { lsType } from "./types.js";
|
||||
|
||||
// 'normal' implementation
|
||||
const emptyList = {l:[]};
|
||||
|
|
@ -22,7 +12,8 @@ const put = ls => i => elem => ({l: ls.l.with(Number(i), elem)});
|
|||
|
||||
export const ModuleList = {l:[
|
||||
// Type -> Type
|
||||
...typedFnType(lsType, fnType => fnType
|
||||
...typedFnType(lsType, fnType =>
|
||||
fnType
|
||||
/* in */ (Type)
|
||||
/* out */ (Type)
|
||||
),
|
||||
|
|
@ -31,7 +22,9 @@ export const ModuleList = {l:[
|
|||
{i: emptyList, t: makeGeneric(a => lsType(a))},
|
||||
|
||||
// [a] -> Int -> a
|
||||
...typedFnType(get, fnType => makeGeneric(a => fnType
|
||||
...typedFnType(get, fnType =>
|
||||
makeGeneric(a =>
|
||||
fnType
|
||||
/* in */ (lsType(a))
|
||||
/* out */ (fnType
|
||||
/* in */ (Int)
|
||||
|
|
@ -39,7 +32,9 @@ export const ModuleList = {l:[
|
|||
))),
|
||||
|
||||
// [a] -> Int -> a -> [a]
|
||||
...typedFnType(put, fnType => makeGeneric(a => fnType
|
||||
...typedFnType(put, fnType =>
|
||||
makeGeneric(a =>
|
||||
fnType
|
||||
/* in */ (lsType(a))
|
||||
/* out */ (fnType
|
||||
/* in */ (Int)
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
import { makeListModule } from "../list.js";
|
||||
import { Typed } from "../../typed.js";
|
||||
import { lsType } from "../list.js";
|
||||
|
||||
// just an alias
|
||||
export const Module = lsType(Typed); // a Module is a list of Typeds
|
||||
|
||||
export const ModuleModule = makeListModule(Typed); // the module containing operations on Module
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
import { Char } from "../../primitives/symbols.js";
|
||||
import { lsType } from "../list.js";
|
||||
import { makeListModule } from "../list.js";
|
||||
|
||||
// just an alias
|
||||
export const String = lsType(Char);
|
||||
|
||||
export const ModuleString = makeListModule(Char);
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { Type } from "../metacircular.js";
|
||||
import { String } from "../structures/list_types/string.js";
|
||||
import { prodType } from "./product.js";
|
||||
import { makeProductType } from "./product.js";
|
||||
|
||||
export const NominalType = prodType(String, Type);
|
||||
|
||||
export const ModuleNominalType = makeProductType(String, Type);
|
||||
|
||||
export const nominalType = ModuleNominalType.l[5].i; // dirty!!
|
||||
|
|
@ -1,16 +1,7 @@
|
|||
import { makeGeneric } from "../generics/generics.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
import { typedFnType } from "./function.js";
|
||||
|
||||
const symbolProduct = Symbol("Product");
|
||||
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({
|
||||
symbol: symbolProduct,
|
||||
params: [leftType, rightType],
|
||||
})));
|
||||
|
||||
// type constructor
|
||||
export const prodType = leftType => rightType => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
import { Type } from "../type.js";
|
||||
import { typedFnType } from "./types.js";
|
||||
import { prodType } from "./types.js";
|
||||
|
||||
// In JS, all products are encoded in the same way:
|
||||
const constructor = left => right => ({left, right});
|
||||
|
|
@ -20,7 +11,8 @@ const getRight = product => product.right;
|
|||
export const ModuleProduct = {l: [
|
||||
// binary type constructor
|
||||
// Type -> Type -> Type
|
||||
...typedFnType(prodType, fnType => fnType
|
||||
...typedFnType(prodType, fnType =>
|
||||
fnType
|
||||
(Type)
|
||||
(fnType
|
||||
(Type)
|
||||
|
|
@ -29,7 +21,9 @@ export const ModuleProduct = {l: [
|
|||
),
|
||||
|
||||
// a -> b -> (a, b)
|
||||
...typedFnType(constructor, fnType => makeGeneric((a, b) => fnType
|
||||
...typedFnType(constructor, fnType =>
|
||||
makeGeneric((a, b) =>
|
||||
fnType
|
||||
(a)
|
||||
(fnType
|
||||
(b)
|
||||
|
|
@ -38,13 +32,17 @@ export const ModuleProduct = {l: [
|
|||
)),
|
||||
|
||||
// (a, b) -> a
|
||||
...typedFnType(getLeft, fnType => makeGeneric((a, b) => fnType
|
||||
...typedFnType(getLeft, fnType =>
|
||||
makeGeneric((a, b) =>
|
||||
fnType
|
||||
(prodType(a)(b))
|
||||
(a)
|
||||
)),
|
||||
|
||||
// (a, b) -> b
|
||||
...typedFnType(getRight, fnType => makeGeneric((a, b) => fnType
|
||||
...typedFnType(getRight, fnType =>
|
||||
makeGeneric((a, b) =>
|
||||
fnType
|
||||
(prodType(a)(b))
|
||||
(b)
|
||||
)),
|
||||
|
|
|
|||
|
|
@ -1,18 +1,8 @@
|
|||
import { prodType } from "./product.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { DefaultMap } from "../util.js";
|
||||
import { typedFnType } from "./function.js";
|
||||
import { prodType } from "./types.js";
|
||||
import { Type } from "../type.js";
|
||||
import { typedFnType } from "./types.js";
|
||||
import { makeGeneric } from "../generics/generics.js";
|
||||
|
||||
const symbolSum = Symbol("Sum");
|
||||
|
||||
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({
|
||||
symbol: symbolSum,
|
||||
params: [leftType, rightType],
|
||||
})));
|
||||
|
||||
// type constructor
|
||||
export const sumType = leftType => rightType => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
import { sumType } from "./types.js";
|
||||
|
||||
const constructorLeft = left => ({variant: "L", value: left });
|
||||
const constructorRight = right => ({variant: "R", value: right});
|
||||
|
|
@ -26,7 +16,8 @@ const match = sum => handlers => sum.variant === "L"
|
|||
export const ModuleSum = {l:[
|
||||
// binary type constructor
|
||||
// Type -> Type -> Type
|
||||
...typedFnType(sumType, fnType => fnType
|
||||
...typedFnType(sumType, fnType =>
|
||||
fnType
|
||||
(Type)
|
||||
(fnType
|
||||
(Type)
|
||||
|
|
@ -35,19 +26,25 @@ export const ModuleSum = {l:[
|
|||
),
|
||||
|
||||
// a -> a | b
|
||||
...typedFnType(constructorLeft, fnType => makeGeneric((a, b) => fnType
|
||||
...typedFnType(constructorLeft, fnType =>
|
||||
makeGeneric((a, b) =>
|
||||
fnType
|
||||
(a)
|
||||
(sumType(a)(b))
|
||||
)),
|
||||
|
||||
// b -> a | b
|
||||
...typedFnType(constructorRight, fnType => makeGeneric((a, b) => fnType
|
||||
...typedFnType(constructorRight, fnType =>
|
||||
makeGeneric((a, b) =>
|
||||
fnType
|
||||
(b)
|
||||
(sumType(a)(b))
|
||||
)),
|
||||
|
||||
// a | b -> (a -> c, b-> c) -> c
|
||||
...typedFnType(match, fnType => makeGeneric((a, b, c) => fnType
|
||||
...typedFnType(match, fnType =>
|
||||
makeGeneric((a, b, c) =>
|
||||
fnType
|
||||
(sumType(a)(b))
|
||||
(fnType
|
||||
(prodType
|
||||
|
|
|
|||
74
structures/types.js
Normal file
74
structures/types.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// to break up dependency cycles, type constructors are defined in their own JS module
|
||||
|
||||
import { DefaultMap } from "../util.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');
|
||||
const fnTypeRegistry = new DefaultMap(inType => new DefaultMap(outType => ({
|
||||
symbol: symbolFunction,
|
||||
params: [inType, outType],
|
||||
})));
|
||||
// type constructor
|
||||
export const fnType = inType => outType => fnTypeRegistry.getdefault(inType, true).getdefault(outType, true);
|
||||
|
||||
// Convenience function. Wrapper around function below.
|
||||
export const typedFnType = (instance, callback) => {
|
||||
const [t, typesOfFns] = typedFnType2(callback);
|
||||
const res = [
|
||||
{ i: instance, t },
|
||||
...typesOfFns,
|
||||
];
|
||||
return res;
|
||||
};
|
||||
// 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 typedFnType2 = callback => {
|
||||
const fnTs = [];
|
||||
const wrappedFnType = inType => outType => {
|
||||
const fnT = fnType(inType)(outType);
|
||||
fnTs.push(fnT);
|
||||
return fnT;
|
||||
};
|
||||
const t = callback(wrappedFnType); // force evaluation
|
||||
return [
|
||||
t,
|
||||
fnTs.map(fnT => ({ i: fnT, t: Function })),
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
// Sum type
|
||||
|
||||
const symbolSum = Symbol("Sum");
|
||||
const sumTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({
|
||||
symbol: symbolSum,
|
||||
params: [leftType, rightType],
|
||||
})));
|
||||
// type constructor
|
||||
export const sumType = leftType => rightType => sumTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
|
||||
|
||||
// Product type
|
||||
|
||||
const symbolProduct = Symbol("Product");
|
||||
const productTypeRegistry = new DefaultMap(leftType => new DefaultMap(rightType => ({
|
||||
symbol: symbolProduct,
|
||||
params: [leftType, rightType],
|
||||
})));
|
||||
// type constructor
|
||||
export const prodType = leftType => rightType => productTypeRegistry.getdefault(leftType, true).getdefault(rightType, true);
|
||||
|
||||
|
||||
// List type
|
||||
|
||||
const symbolList = Symbol('List');
|
||||
const listTypeRegistry = new DefaultMap(elementType => ({
|
||||
symbol: symbolList,
|
||||
params: [elementType],
|
||||
}));
|
||||
// type constructor
|
||||
export const lsType = elementType => listTypeRegistry.getdefault(elementType, true);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Bool } from "./primitives/symbols.js";
|
||||
import { typedFnType } from "./structures/function.js";
|
||||
import { Bool } from "./primitives/types.js";
|
||||
import { typedFnType } from "./structures/types.js";
|
||||
import { deepEqual } from "./util.js";
|
||||
|
||||
// TODO: 'Type' (and its instances) are itself instances of (String,[Type]) (=the product type of String and list of Type)
|
||||
|
|
@ -14,24 +14,26 @@ export const eqType = deepEqual;
|
|||
|
||||
// a module is just a set of typed objects
|
||||
// each 'typed object' is implicitly an instance of TypeLink (defined below)
|
||||
export const ModuleMetaCircular = {l:[
|
||||
export const ModuleType = {l:[
|
||||
// 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
|
||||
// Type :: Type
|
||||
{i: Type, t: Type},
|
||||
|
||||
// ...typedFnType(getSymbol, fnType => fnType({in: Type, out: Int})),
|
||||
|
||||
// ...typedFnType(getParams, fnType => fnType({in: Type, out: lsType(Type)})),
|
||||
|
||||
...typedFnType(eqType, fnType => fnType({
|
||||
in: Type,
|
||||
out: fnType({
|
||||
in: Type,
|
||||
out: Bool,
|
||||
})})),
|
||||
// Type -> Type -> Bool
|
||||
...typedFnType(eqType, fnType =>
|
||||
fnType
|
||||
(Type)
|
||||
(fnType
|
||||
(Type)
|
||||
(Bool)
|
||||
)),
|
||||
]};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { makeGeneric } from "../generics/generics";
|
||||
import { Type } from "../metacircular";
|
||||
import { typedFnType } from "../structures/function";
|
||||
import { Bool, Byte, Char, Double, Int } from "../primitives/symbols";
|
||||
import { Type } from "../type";
|
||||
import { typedFnType } from "../structures/types";
|
||||
import { Bool, Byte, Char, Double, Int } from "../primitives/types";
|
||||
import { deepEqual } from "../util";
|
||||
import { eqDictType } from "./eq_type";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { makeGeneric } from "../generics/generics.js";
|
||||
import { addDouble, mulDouble } from "../primitives/double.js";
|
||||
import { addInt, mulInt } from "../primitives/int.js";
|
||||
import { Type } from "../metacircular.js";
|
||||
import { typedFnType, typedFnType2 } from "../structures/function.js";
|
||||
import { Double, Int } from "../primitives/symbols.js";
|
||||
import { Type } from "../type.js";
|
||||
import { typedFnType, typedFnType2 } from "../structures/types.js";
|
||||
import { Double, Int } from "../primitives/types.js";
|
||||
import { numDictType } from "./num_type.js";
|
||||
|
||||
export const getAdd = numDict => numDict.add;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { assign } from "../generics/generics.js";
|
||||
import { makeGeneric } from "../generics/generics.js";
|
||||
import { fnType } from "../structures/function.js";
|
||||
import { Double, Int } from "../primitives/symbols.js";
|
||||
import { Double, Int } from "../primitives/types.js";
|
||||
import { getMul, NumInstances } from "./num.js";
|
||||
import { numDictType } from "./num_type.js";
|
||||
|
||||
|
|
|
|||
12
typed.js
12
typed.js
|
|
@ -1,5 +1,5 @@
|
|||
import { fnType } from "./structures/function.js";
|
||||
import { Type } from "./metacircular.js";
|
||||
import { typedFnType } from "./structures/types.js";
|
||||
import { Type } from "./type.js";
|
||||
|
||||
// Everything is (implicitly) typed by the Any type.
|
||||
export const Any = { symbol: Symbol('Any'), params: [] };
|
||||
|
|
@ -10,13 +10,9 @@ export const Typed = { symbol: Symbol('Typed'), params: [] };
|
|||
const getInst = lnk => lnk.i;
|
||||
const getType = lnk => lnk.t;
|
||||
|
||||
const Typed_to_Type = fnType({in: Any, out: Type});
|
||||
|
||||
export const ModuleTyped = {l:[
|
||||
{i: Typed, t: Type},
|
||||
|
||||
{i: Typed_to_Type, t: Type},
|
||||
|
||||
{i: getInst, t: Typed_to_Type},
|
||||
{i: getType, t: Typed_to_Type},
|
||||
...typedFnType(getInst, fnType => fnType(Typed)(Type)),
|
||||
...typedFnType(getType, fnType => fnType(Typed)(Type)),
|
||||
]};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue