add interactive prompt

This commit is contained in:
Joeri Exelmans 2025-03-20 09:54:11 +01:00
parent ce192b49f2
commit 94efde3e65
22 changed files with 599 additions and 138 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

View file

@ -1,6 +1,5 @@
import { Bool, Int } from "../primitives/symbols.js";
import { fnType, lsType } from "../type_registry.js"; import { fnType, lsType } from "../type_registry.js";
import { deepEqual } from "../util.js"; import { deepEqual, pretty } from "../util.js";
export const makeGeneric = callback => { export const makeGeneric = callback => {
// type variables to make available: // type variables to make available:
@ -32,12 +31,11 @@ const occurring = (type, typeVars) => {
return new Set(); return new Set();
} }
// merge_int(1, 2) => conflict(1,2)
// merge_list_of_int([1], [2]) => [conflict(1,2)]
import { inspect } from 'node:util'; // merge {i: [1], t: List_of_Int} ->
function pretty(obj) {
return inspect(obj, {colors: true});
}
export const matchGeneric = ( export const matchGeneric = (
{typeVars: formalTypeVars, type: formalType}, {typeVars: formalTypeVars, type: formalType},

View file

@ -9,8 +9,8 @@ const ListOfByte = lsType(Byte);
const serializeFnType = fnType({in: Serializable, out: ListOfByte}); const serializeFnType = fnType({in: Serializable, out: ListOfByte});
const deserializeFnType = fnType({in: ListOfByte, out: Serializable}); const deserializeFnType = fnType({in: ListOfByte, out: Serializable});
export const ModuleSerializable = [ export const ModuleSerializable = {l:[
{i: Serializable , t: Type}, {i: Serializable , t: Type},
{i: serializeFnType , t: Function}, {i: serializeFnType , t: Function},
{i: deserializeFnType, t: Function}, {i: deserializeFnType, t: Function},
]; ]};

View file

@ -32,8 +32,8 @@ import {Function} from "../metacircular.js";
export const makeIdFn = typ => { export const makeIdFn = typ => {
const Typ_to_Typ = fnType({in: typ, out: typ}); const Typ_to_Typ = fnType({in: typ, out: typ});
const id = x => x; const id = x => x;
return [ return {l:[
{i: id , t: Typ_to_Typ}, {i: id , t: Typ_to_Typ},
{i: Typ_to_Typ, t: Function}, {i: Typ_to_Typ, t: Function},
]; ]};
}; };

View file

@ -36,15 +36,15 @@ export const makeSquare = ({i: mul, t: mulFunction}) => {
} }
const square = x => mul(x)(x); const square = x => mul(x)(x);
const squareFunction = fnType({in: numType, out: numType}); const squareFunction = fnType({in: numType, out: numType});
return [ return {l:[
{i: square , t: squareFunction}, {i: square , t: squareFunction},
{i: squareFunction, t: Function}, {i: squareFunction, t: Function},
]; ]};
}; };
const makeSquareType = fnType({in: Typed, out: Module}); const makeSquareType = fnType({in: Typed, out: Module});
export const ModuleSquare = [ export const ModuleSquare = {l:[
{i: makeSquare , t: makeSquareType}, {i: makeSquare , t: makeSquareType},
{i: makeSquareType, t: Function}, {i: makeSquareType, t: Function},
]; ]};

View file

@ -1,39 +0,0 @@
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 { lsType, prodType, sumType } from "../type_registry.js";
const ListOfDouble = lsType(Double);
const ListOfDoubleModule = makeListModule(Double);
const ListOfListOfDouble = lsType(ListOfDouble);
const ListOfListOfDoubleModule = makeListModule(ListOfDouble);
const ListOfByte = lsType(Byte);
const ListOfByteModule = makeListModule(Byte);
export const ModuleValues = [
{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,
...ListOfListOfDoubleModule,
...ListOfByteModule,
...makeProductType(Int, Bool),
...makeSumType(Int, Bool),
{i: {left: 42n, right: true}, t: prodType(Int, Bool)},
{i: {variant: "L", value: 100n}, t: sumType(Int, Bool)},
];

199
main.js
View file

@ -3,92 +3,169 @@ import {ModuleTyped} from "./typed.js";
import {ModuleBool} from "./primitives/bool.js"; import {ModuleBool} from "./primitives/bool.js";
import { Double_to_Double_to_Double, ModuleDouble, mulDouble } from "./primitives/double.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_to_Int_to_Int, ModuleInt, mulInt} from "./primitives/int.js";
import {Int} from "./primitives/symbols.js";
import { makeSquare } from "./lib/square.js"; import { makeSquare } from "./lib/square.js";
import {makeIdFn} from "./lib/id.js"; import {makeIdFn} from "./lib/id.js";
import {ModuleValues} from "./lib/values.js";
import {DefaultMap} from "./util.js"; import {DefaultMap, pretty} from "./util.js";
import { ModuleModule } from "./structures/module.js"; import { ModuleModule } from "./structures/module.js";
import { ModuleList } from "./structures/list.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 { lsType, prodType, sumType } from "./type_registry.js";
class Context { class Context {
constructor(mod) { constructor(mod) {
// input type -> Function-signature
this.functionsFrom = new DefaultMap(() => []); this.functionsFrom = new DefaultMap(() => []);
this.functionsTo = new DefaultMap(() => []); this.functionsTo = new DefaultMap(() => []);
this.types = new DefaultMap(() => []); this.types = new DefaultMap(() => []);
this.instances = new DefaultMap(() => []); this.instances = new DefaultMap(() => []);
for (const {i, t} of mod.l) {
for (const {i, t} of mod) { this.types.getdefault(i, true).push(t);
this.addInstance({i, t}); this.instances.getdefault(t, true).push(i);
} }
const callFunctionOnEveryValue = (fn, fnType, indent=1) => { for (const fnType of this.instances.getdefault(Function)) {
const inType = getIn(fnType); for (const fn of this.instances.getdefault(fnType)) {
const outType = getOut(fnType); this.functionsFrom.getdefault(getIn(fnType), true).push(fn);
console.log(); this.functionsTo.getdefault(getOut(fnType), true).push(fn);
if (fn.name !== "") {
console.log("--".repeat(indent), fn, ':', fnType);
}
for (const i of this.instances.getdefault(inType)) {
try {
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);
}
}
} catch (e) {
console.log("--".repeat(indent+1), i, `-> (exception: ${e})`);
}
}
}
for (const fntypes of this.functionsFrom.m.values()) {
for (const fntype of fntypes) {
for (const fn of this.instances.getdefault(fntype)) {
callFunctionOnEveryValue(fn, fntype);
} }
} }
} }
} // const callFunctionOnEveryValue = (fn, fnType, indent=1) => {
// const inType = getIn(fnType);
addInstance({i, t}) { // const outType = getOut(fnType);
const arr = this.types.getdefault(i, true); // console.log();
arr.push(t); // if (fn.name !== "") {
const arrI = this.instances.getdefault(t, true); // console.log("--".repeat(indent), fn, ':', fnType);
arrI.push(i); // }
if (t === Function) { // for (const i of this.instances.getdefault(inType)) {
const arr = this.functionsFrom.getdefault(getIn(i), true); // try {
arr.push(i); // const result = fn(i);
const arrTo = this.functionsTo.getdefault(getOut(i), true); // console.log("--".repeat(indent+1), i, '->', result);
arrTo.push(i); // if (this.types.getdefault(outType).includes(Function)) {
} // if (indent < 5) {
else { // callFunctionOnEveryValue(result, outType, indent+2);
} // }
} // }
// } catch (e) {
// console.log("--".repeat(indent+1), i, `-> (exception: ${e})`);
// }
// }
// }
// for (const fntypes of this.functionsFrom.m.values()) {
// for (const fntype of fntypes) {
// for (const fn of this.instances.getdefault(fntype)) {
// callFunctionOnEveryValue(fn, fntype);
// }
// }
// }
// }
} }
const ListOfDouble = lsType(Double);
const ListOfDoubleModule = makeListModule(Double);
const ctx = new Context([ const ListOfListOfDouble = lsType(ListOfDouble);
...ModuleMetaCircular, const ListOfListOfDoubleModule = makeListModule(ListOfDouble);
...ModuleTyped,
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)},
]};
const ctx = new Context({l:[
...ModuleMetaCircular.l,
...ModuleTyped.l,
// ...ModuleConformable, // ...ModuleConformable,
// ...ModuleConformanceCheckConforms, // ...ModuleConformanceCheckConforms,
// ...ModuleNum, // ...ModuleNum,
// ...ModuleEq, // ...ModuleEq,
...ModuleBool, ...ModuleBool.l,
...ModuleInt, ...ModuleInt.l,
...ModuleDouble, ...ModuleDouble.l,
// ...ModuleSquare, // ...ModuleSquare,
// ...ModuleList, // ...ModuleList,
...makeIdFn(Int), ...makeIdFn(Int).l,
...makeSquare({i: mulInt, t: Int_to_Int_to_Int}), ...makeSquare({i: mulInt, t: Int_to_Int_to_Int}).l,
...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}), ...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}).l,
...ModuleList, ...ModuleList.l,
...ModuleValues, ...ModuleValues.l,
...ModuleModule, ...ModuleModule.l,
]); ]});
import { input, select } from '@inquirer/prompts';
const makeChoice = ([i, t]) => {
return {
value: {i, t: t[0]},
name: pretty(i),
description: `${pretty(i)} :: ${pretty(t[0])}`,
short: `${pretty(i)} :: ${pretty(t[0])}`,
};
}
let {i,t} = await select({
message: "Choose value:",
choices: [...ctx.types.entries()].map(makeChoice),
});
while (true) {
let fn, fnType;
if (ctx.types.getdefault(t).includes(Function)) {
fn = i;
fnType = t;
const s = await select({
message: "Select input for function:",
choices: ctx.instances.getdefault(getIn(t))
.map(i => [i, ctx.types.getdefault(i)])
.map(makeChoice),
});
i = s.i;
t = s.t;
}
else{
fn = await select({
message: "Choose function:",
choices: [...ctx.functionsFrom.getdefault(t).map(fn => ({
value: fn,
name: pretty(fn),
description: `${pretty(fn)} :: ${pretty(ctx.types.getdefault(fn)[0])}`,
short: `${pretty(fn)} :: ${pretty(ctx.types.getdefault(fn)[0])}`,
})
)],
});
fnType = ctx.types.getdefault(fn)[0];
}
const result = fn(i);
t = getOut(fnType);
console.log("result =", result, "::", t);
i = result;
}

View file

@ -10,7 +10,7 @@ export const getOut = fn => fn.out;
// a module is just a set of typed objects // a module is just a set of typed objects
// each 'typed object' is implicitly an instance of TypeLink (defined below) // each 'typed object' is implicitly an instance of TypeLink (defined below)
export const ModuleMetaCircular = [ export const ModuleMetaCircular = {l:[
// TODO? maybe follow Lean so // TODO? maybe follow Lean so
// Type.{0} : Type.{1} // Type.{0} : Type.{1}
// Type.{1} : Type.{2} // Type.{1} : Type.{2}
@ -28,4 +28,4 @@ export const ModuleMetaCircular = [
{i: getIn , t: fnType({in: Function, out: Type})}, {i: getIn , t: fnType({in: Function, out: Type})},
{i: getOut, t: fnType({in: Function, out: Type})}, {i: getOut, t: fnType({in: Function, out: Type})},
]; ]};

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"dependencies": {
"@inquirer/prompts": "^7.4.0"
}
}

374
pnpm-lock.yaml generated Normal file
View file

@ -0,0 +1,374 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
'@inquirer/prompts':
specifier: ^7.4.0
version: 7.4.0
packages:
'@inquirer/checkbox@4.1.4':
resolution: {integrity: sha512-d30576EZdApjAMceijXA5jDzRQHT/MygbC+J8I7EqA6f/FRpYxlRtRJbHF8gHeWYeSdOuTEJqonn7QLB1ELezA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/confirm@5.1.8':
resolution: {integrity: sha512-dNLWCYZvXDjO3rnQfk2iuJNL4Ivwz/T2+C3+WnNfJKsNGSuOs3wAo2F6e0p946gtSAk31nZMfW+MRmYaplPKsg==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/core@10.1.9':
resolution: {integrity: sha512-sXhVB8n20NYkUBfDYgizGHlpRVaCRjtuzNZA6xpALIUbkgfd2Hjz+DfEN6+h1BRnuxw0/P4jCIMjMsEOAMwAJw==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/editor@4.2.9':
resolution: {integrity: sha512-8HjOppAxO7O4wV1ETUlJFg6NDjp/W2NP5FB9ZPAcinAlNT4ZIWOLe2pUVwmmPRSV0NMdI5r/+lflN55AwZOKSw==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/expand@4.0.11':
resolution: {integrity: sha512-OZSUW4hFMW2TYvX/Sv+NnOZgO8CHT2TU1roUCUIF2T+wfw60XFRRp9MRUPCT06cRnKL+aemt2YmTWwt7rOrNEA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/figures@1.0.11':
resolution: {integrity: sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==}
engines: {node: '>=18'}
'@inquirer/input@4.1.8':
resolution: {integrity: sha512-WXJI16oOZ3/LiENCAxe8joniNp8MQxF6Wi5V+EBbVA0ZIOpFcL4I9e7f7cXse0HJeIPCWO8Lcgnk98juItCi7Q==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/number@3.0.11':
resolution: {integrity: sha512-pQK68CsKOgwvU2eA53AG/4npRTH2pvs/pZ2bFvzpBhrznh8Mcwt19c+nMO7LHRr3Vreu1KPhNBF3vQAKrjIulw==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/password@4.0.11':
resolution: {integrity: sha512-dH6zLdv+HEv1nBs96Case6eppkRggMe8LoOTl30+Gq5Wf27AO/vHFgStTVz4aoevLdNXqwE23++IXGw4eiOXTg==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/prompts@7.4.0':
resolution: {integrity: sha512-EZiJidQOT4O5PYtqnu1JbF0clv36oW2CviR66c7ma4LsupmmQlUwmdReGKRp456OWPWMz3PdrPiYg3aCk3op2w==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/rawlist@4.0.11':
resolution: {integrity: sha512-uAYtTx0IF/PqUAvsRrF3xvnxJV516wmR6YVONOmCWJbbt87HcDHLfL9wmBQFbNJRv5kCjdYKrZcavDkH3sVJPg==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/search@3.0.11':
resolution: {integrity: sha512-9CWQT0ikYcg6Ls3TOa7jljsD7PgjcsYEM0bYE+Gkz+uoW9u8eaJCRHJKkucpRE5+xKtaaDbrND+nPDoxzjYyew==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/select@4.1.0':
resolution: {integrity: sha512-z0a2fmgTSRN+YBuiK1ROfJ2Nvrpij5lVN3gPDkQGhavdvIVGHGW29LwYZfM/j42Ai2hUghTI/uoBuTbrJk42bA==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/type@3.0.5':
resolution: {integrity: sha512-ZJpeIYYueOz/i/ONzrfof8g89kNdO2hjGuvULROo3O8rlB2CRtSseE5KeirnyE4t/thAn/EwvS/vuQeJCn+NZg==}
engines: {node: '>=18'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
ansi-escapes@4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
chardet@0.7.0:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
cli-width@4.1.0:
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
engines: {node: '>= 12'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
external-editor@3.1.0:
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
engines: {node: '>=4'}
iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
mute-stream@2.0.0:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
type-fest@0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
yoctocolors-cjs@2.1.2:
resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==}
engines: {node: '>=18'}
snapshots:
'@inquirer/checkbox@4.1.4':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/figures': 1.0.11
'@inquirer/type': 3.0.5
ansi-escapes: 4.3.2
yoctocolors-cjs: 2.1.2
'@inquirer/confirm@5.1.8':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
'@inquirer/core@10.1.9':
dependencies:
'@inquirer/figures': 1.0.11
'@inquirer/type': 3.0.5
ansi-escapes: 4.3.2
cli-width: 4.1.0
mute-stream: 2.0.0
signal-exit: 4.1.0
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.2
'@inquirer/editor@4.2.9':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
external-editor: 3.1.0
'@inquirer/expand@4.0.11':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
yoctocolors-cjs: 2.1.2
'@inquirer/figures@1.0.11': {}
'@inquirer/input@4.1.8':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
'@inquirer/number@3.0.11':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
'@inquirer/password@4.0.11':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
ansi-escapes: 4.3.2
'@inquirer/prompts@7.4.0':
dependencies:
'@inquirer/checkbox': 4.1.4
'@inquirer/confirm': 5.1.8
'@inquirer/editor': 4.2.9
'@inquirer/expand': 4.0.11
'@inquirer/input': 4.1.8
'@inquirer/number': 3.0.11
'@inquirer/password': 4.0.11
'@inquirer/rawlist': 4.0.11
'@inquirer/search': 3.0.11
'@inquirer/select': 4.1.0
'@inquirer/rawlist@4.0.11':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/type': 3.0.5
yoctocolors-cjs: 2.1.2
'@inquirer/search@3.0.11':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/figures': 1.0.11
'@inquirer/type': 3.0.5
yoctocolors-cjs: 2.1.2
'@inquirer/select@4.1.0':
dependencies:
'@inquirer/core': 10.1.9
'@inquirer/figures': 1.0.11
'@inquirer/type': 3.0.5
ansi-escapes: 4.3.2
yoctocolors-cjs: 2.1.2
'@inquirer/type@3.0.5': {}
ansi-escapes@4.3.2:
dependencies:
type-fest: 0.21.3
ansi-regex@5.0.1: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
chardet@0.7.0: {}
cli-width@4.1.0: {}
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
color-name@1.1.4: {}
emoji-regex@8.0.0: {}
external-editor@3.1.0:
dependencies:
chardet: 0.7.0
iconv-lite: 0.4.24
tmp: 0.0.33
iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
is-fullwidth-code-point@3.0.0: {}
mute-stream@2.0.0: {}
os-tmpdir@1.0.2: {}
safer-buffer@2.1.2: {}
signal-exit@4.1.0: {}
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
tmp@0.0.33:
dependencies:
os-tmpdir: 1.0.2
type-fest@0.21.3: {}
wrap-ansi@6.2.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
yoctocolors-cjs@2.1.2: {}

View file

@ -7,9 +7,9 @@ const eqBool = x => y => x === y;
const Bool_to_Bool = fnType({in: Bool, out: Bool}); const Bool_to_Bool = fnType({in: Bool, out: Bool});
const Bool_to_Bool_to_Bool = fnType({in: Bool, out: Bool_to_Bool}); const Bool_to_Bool_to_Bool = fnType({in: Bool, out: Bool_to_Bool});
export const ModuleBool = [ export const ModuleBool = {l:[
{i: Bool , t: Type }, {i: Bool , t: Type },
{i: Bool_to_Bool , t: Function }, {i: Bool_to_Bool , t: Function },
{i: Bool_to_Bool_to_Bool , t: Function }, {i: Bool_to_Bool_to_Bool , t: Function },
{i: eqBool , t: Bool_to_Bool_to_Bool }, {i: eqBool , t: Bool_to_Bool_to_Bool },
]; ]};

View file

@ -7,9 +7,9 @@ const eqByte = x => y => x === y;
const Byte_to_Bool = fnType({in: Byte, out: Bool}); const Byte_to_Bool = fnType({in: Byte, out: Bool});
const Byte_to_Byte_to_Bool = fnType({in: Byte, out: Byte_to_Bool}); const Byte_to_Byte_to_Bool = fnType({in: Byte, out: Byte_to_Bool});
export const ModuleByte = [ export const ModuleByte = {l:[
{i: Byte , t: Type }, {i: Byte , t: Type },
{i: Byte_to_Bool , t: Function }, {i: Byte_to_Bool , t: Function },
{i: Byte_to_Byte_to_Bool , t: Function }, {i: Byte_to_Byte_to_Bool , t: Function },
{i: eqByte , t: Byte_to_Byte_to_Bool }, {i: eqByte , t: Byte_to_Byte_to_Bool },
]; ]};

View file

@ -13,7 +13,7 @@ export const Double_to_Double_to_Double = fnType({in: Double, out: Double_to_Dou
export const Double_to_Double_to_Bool = fnType({in: Double, out: Double_to_Bool}); export const Double_to_Double_to_Bool = fnType({in: Double, out: Double_to_Bool});
export const ModuleDouble = [ 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_Double, t: Function },
@ -24,4 +24,4 @@ export const ModuleDouble = [
{i: addDouble , t: Double_to_Double_to_Double }, {i: addDouble , t: Double_to_Double_to_Double },
{i: mulDouble , t: Double_to_Double_to_Double }, {i: mulDouble , t: Double_to_Double_to_Double },
{i: eqDouble , t: Double_to_Double_to_Bool }, {i: eqDouble , t: Double_to_Double_to_Bool },
]; ]};

View file

@ -12,8 +12,11 @@ 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_Int = fnType({in: Int, out: Int_to_Int});
export const Int_to_Int_to_Bool = fnType({in: Int, out: Int_to_Bool}); 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 = [
export const ModuleInt = {l:[
{i: Int , t: Type }, {i: Int , t: Type },
{i: Int_to_Int_to_Int , t: Function }, {i: Int_to_Int_to_Int , t: Function },
@ -24,4 +27,4 @@ export const ModuleInt = [
{i: addInt , t: Int_to_Int_to_Int }, {i: addInt , t: Int_to_Int_to_Int },
{i: mulInt , t: Int_to_Int_to_Int }, {i: mulInt , t: Int_to_Int_to_Int },
{i: eqInt , t: Int_to_Int_to_Bool }, {i: eqInt , t: Int_to_Int_to_Bool },
]; ]};

17
progress.txt Normal file
View file

@ -0,0 +1,17 @@
status:
- everything is properly typed, up to the meta-circular level
- primitives
- structures: list, product, sum
can compose structures, e.g., create list of list of product of sum of ...
list type is specialized for ListOfByte to use Uint8Array
- generics currently implemented in two ways:
1) similar to "templates" (as in C++):
a generic function or type is a function that takes a Type, and produces a specific variant
2) experimental implementation of polymorphic types and type inferencing
values currently treated as white-box, hardcoded generic types (e.g., list, function) in type inferencing algorithm
todo:
- interfaces via typeclasses?
- type inferencing can be reduced to finding a graph isomorphism?

View file

@ -6,10 +6,10 @@ import { Module } from "./module.js";
const Type_to_Type = fnType({in: Type, out: Type}); const Type_to_Type = fnType({in: Type, out: Type});
const Type_to_Module = fnType({in: Type, out: Module}); const Type_to_Module = fnType({in: Type, out: Module});
export const ModuleList = [ export const ModuleList = {l:[
{i: lsType , t: Type_to_Type}, {i: lsType , t: Type_to_Type},
{i: Type_to_Type , t: Function}, {i: Type_to_Type , t: Function},
{i: makeListModule, t: Type_to_Module}, {i: makeListModule, t: Type_to_Module},
{i: Type_to_Module, t: Function}, {i: Type_to_Module, t: Function},
]; ]};

View file

@ -50,20 +50,20 @@ export const makeListModule = elementType => {
if (elementType === Byte) { if (elementType === Byte) {
// specialization: use Uint8Array instead of JS array // specialization: use Uint8Array instead of JS array
return [ return {l:[
...common, ...common,
{i: byteListImpl.emptyList , t: ListOfElement}, {i: byteListImpl.emptyList , t: ListOfElement},
{i: byteListImpl.get , t: getFnType}, {i: byteListImpl.get , t: getFnType},
{i: byteListImpl.put , t: putFnType}, {i: byteListImpl.put , t: putFnType},
]; ]};
} }
else { else {
return [ return {l:[
...common, ...common,
{i: emptyList , t: ListOfElement}, {i: emptyList , t: ListOfElement},
{i: get , t: getFnType}, {i: get , t: getFnType},
{i: put , t: putFnType}, {i: put , t: putFnType},
// {i: push , t: pushFnType}, // {i: push , t: pushFnType},
]; ]};
} }
}; };

View file

@ -16,7 +16,7 @@ export const makeProductType = (leftType, rightType) => {
const constructorBoundType = fnType({in: rightType, out: pType}); const constructorBoundType = fnType({in: rightType, out: pType});
const constructorType = fnType({in: leftType , out: constructorBoundType}); const constructorType = fnType({in: leftType , out: constructorBoundType});
return [ return {l:[
{i: pType, t: Type}, {i: pType, t: Type},
{i: getLeft , t: leftFnType}, {i: getLeft , t: leftFnType},
@ -27,5 +27,5 @@ export const makeProductType = (leftType, rightType) => {
{i: constructor , t: constructorType}, {i: constructor , t: constructorType},
{i: constructorType , t: Function}, {i: constructorType , t: Function},
{i: constructorBoundType, t: Function}, {i: constructorBoundType, t: Function},
]; ]};
}; };

View file

@ -5,6 +5,8 @@ import { Module } from "./module.js";
const constructorLeft = left => ({variant: "L", value: left }); const constructorLeft = left => ({variant: "L", value: left });
const constructorRight = right => ({variant: "R", value: right}); const constructorRight = right => ({variant: "R", value: right});
// (<uuid>, product(double, double)): product(int, type)
// signature: // signature:
// sum-type -> (leftType -> resultType, rightType -> resultType) -> resultType // sum-type -> (leftType -> resultType, rightType -> resultType) -> resultType
const match = sum => handlers => sum.variant === "L" const match = sum => handlers => sum.variant === "L"
@ -26,13 +28,13 @@ export const makeSumType = (leftType, rightType) => {
fnType({in: rightType, out: returnType}), // handler function for right variant fnType({in: rightType, out: returnType}), // handler function for right variant
); );
const matchFnType = fnType({in: sType, out: fnType({in: handlersType, out: returnType})}); const matchFnType = fnType({in: sType, out: fnType({in: handlersType, out: returnType})});
return [ return {l:[
{i: match , t: matchFnType}, {i: match , t: matchFnType},
{i: matchFnType, t: Function}, {i: matchFnType, t: Function},
]; ]};
}; };
return [ return {l:[
{i: sType , t: Type}, {i: sType , t: Type},
{i: constructorLeft , t: constructorLeftType}, {i: constructorLeft , t: constructorLeftType},
{i: constructorRight , t: constructorRightType}, {i: constructorRight , t: constructorRightType},
@ -40,5 +42,5 @@ export const makeSumType = (leftType, rightType) => {
{i: constructorRightType, t: Function}, {i: constructorRightType, t: Function},
{i: makeMatchFn, t: fnType({in: Type, out: Module})}, {i: makeMatchFn, t: fnType({in: Type, out: Module})},
]; ]};
}; };

View file

@ -62,3 +62,19 @@ export const sumType = (leftType, rightType) => {
return 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;
// }
// }

View file

@ -8,11 +8,11 @@ const getType = lnk => lnk.t;
const Typed_to_Type = fnType({in: Typed, out: Type}); const Typed_to_Type = fnType({in: Typed, out: Type});
export const ModuleTyped = [ export const ModuleTyped = {l:[
{i: Typed, t: Type}, {i: Typed, t: Type},
{i: Typed_to_Type, t: Function}, {i: Typed_to_Type, t: Function},
{i: getInst, t: Typed_to_Type}, {i: getInst, t: Typed_to_Type},
{i: getType, t: Typed_to_Type}, {i: getType, t: Typed_to_Type},
]; ]};

View file

@ -40,3 +40,10 @@ export class DefaultMap {
return this.m.entries(); return this.m.entries();
} }
} }
import { inspect } from 'node:util';
export function pretty(obj) {
return inspect(obj, {colors: true});
}