From 94efde3e659264c259bf3ecfe02f909da05fb64a Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Thu, 20 Mar 2025 09:54:11 +0100 Subject: [PATCH] add interactive prompt --- .gitignore | 1 + generics/generics.js | 10 +- interfaces/serializable.js | 4 +- lib/id.js | 4 +- lib/square.js | 8 +- lib/values.js | 39 ---- main.js | 199 ++++++++++++++------ metacircular.js | 4 +- package.json | 5 + pnpm-lock.yaml | 374 +++++++++++++++++++++++++++++++++++++ primitives/bool.js | 4 +- primitives/byte.js | 4 +- primitives/double.js | 4 +- primitives/int.js | 7 +- progress.txt | 17 ++ structures/list.js | 4 +- structures/list_common.js | 8 +- structures/product.js | 4 +- structures/sum.js | 10 +- type_registry.js | 16 ++ typed.js | 4 +- util.js | 7 + 22 files changed, 599 insertions(+), 138 deletions(-) create mode 100644 .gitignore delete mode 100644 lib/values.js create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 progress.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/generics/generics.js b/generics/generics.js index 304de7d..d17273f 100644 --- a/generics/generics.js +++ b/generics/generics.js @@ -1,6 +1,5 @@ -import { Bool, Int } from "../primitives/symbols.js"; import { fnType, lsType } from "../type_registry.js"; -import { deepEqual } from "../util.js"; +import { deepEqual, pretty } from "../util.js"; export const makeGeneric = callback => { // type variables to make available: @@ -32,12 +31,11 @@ const occurring = (type, typeVars) => { 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 = ( {typeVars: formalTypeVars, type: formalType}, diff --git a/interfaces/serializable.js b/interfaces/serializable.js index abac7f6..54498db 100644 --- a/interfaces/serializable.js +++ b/interfaces/serializable.js @@ -9,8 +9,8 @@ const ListOfByte = lsType(Byte); const serializeFnType = fnType({in: Serializable, out: ListOfByte}); const deserializeFnType = fnType({in: ListOfByte, out: Serializable}); -export const ModuleSerializable = [ +export const ModuleSerializable = {l:[ {i: Serializable , t: Type}, {i: serializeFnType , t: Function}, {i: deserializeFnType, t: Function}, -]; +]}; diff --git a/lib/id.js b/lib/id.js index ba19d5a..98c0411 100644 --- a/lib/id.js +++ b/lib/id.js @@ -32,8 +32,8 @@ import {Function} from "../metacircular.js"; export const makeIdFn = typ => { const Typ_to_Typ = fnType({in: typ, out: typ}); const id = x => x; - return [ + return {l:[ {i: id , t: Typ_to_Typ}, {i: Typ_to_Typ, t: Function}, - ]; + ]}; }; diff --git a/lib/square.js b/lib/square.js index 7510a39..5a598cc 100644 --- a/lib/square.js +++ b/lib/square.js @@ -36,15 +36,15 @@ export const makeSquare = ({i: mul, t: mulFunction}) => { } const square = x => mul(x)(x); const squareFunction = fnType({in: numType, out: numType}); - return [ + return {l:[ {i: square , t: squareFunction}, {i: squareFunction, t: Function}, - ]; + ]}; }; const makeSquareType = fnType({in: Typed, out: Module}); -export const ModuleSquare = [ +export const ModuleSquare = {l:[ {i: makeSquare , t: makeSquareType}, {i: makeSquareType, t: Function}, -]; +]}; diff --git a/lib/values.js b/lib/values.js deleted file mode 100644 index ea9df41..0000000 --- a/lib/values.js +++ /dev/null @@ -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)}, -]; diff --git a/main.js b/main.js index e4553da..2b8294c 100644 --- a/main.js +++ b/main.js @@ -3,92 +3,169 @@ 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 {ModuleValues} from "./lib/values.js"; -import {DefaultMap} from "./util.js"; +import {DefaultMap, pretty} from "./util.js"; import { ModuleModule } from "./structures/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 { lsType, prodType, sumType } from "./type_registry.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}); + for (const {i, t} of mod.l) { + this.types.getdefault(i, true).push(t); + this.instances.getdefault(t, true).push(i); } - const callFunctionOnEveryValue = (fn, fnType, indent=1) => { - const inType = getIn(fnType); - const outType = getOut(fnType); - console.log(); - 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 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 fntypes of this.functionsFrom.m.values()) { - for (const fntype of fntypes) { - for (const fn of this.instances.getdefault(fntype)) { - callFunctionOnEveryValue(fn, fntype); - } - } - } - } - 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 callFunctionOnEveryValue = (fn, fnType, indent=1) => { + // const inType = getIn(fnType); + // const outType = getOut(fnType); + // console.log(); + // 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 ListOfDouble = lsType(Double); +const ListOfDoubleModule = makeListModule(Double); -const ctx = new Context([ - ...ModuleMetaCircular, - ...ModuleTyped, +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)}, +]}; + + +const ctx = new Context({l:[ + ...ModuleMetaCircular.l, + ...ModuleTyped.l, // ...ModuleConformable, // ...ModuleConformanceCheckConforms, // ...ModuleNum, // ...ModuleEq, - ...ModuleBool, - ...ModuleInt, - ...ModuleDouble, + ...ModuleBool.l, + ...ModuleInt.l, + ...ModuleDouble.l, // ...ModuleSquare, // ...ModuleList, - ...makeIdFn(Int), - ...makeSquare({i: mulInt, t: Int_to_Int_to_Int}), - ...makeSquare({i: mulDouble, t: Double_to_Double_to_Double}), - ...ModuleList, - ...ModuleValues, - ...ModuleModule, -]); + ...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, +]}); + +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; +} diff --git a/metacircular.js b/metacircular.js index 3b43d8a..a068734 100644 --- a/metacircular.js +++ b/metacircular.js @@ -10,7 +10,7 @@ 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 = [ +export const ModuleMetaCircular = {l:[ // TODO? maybe follow Lean so // Type.{0} : Type.{1} // Type.{1} : Type.{2} @@ -28,4 +28,4 @@ export const ModuleMetaCircular = [ {i: getIn , t: fnType({in: Function, out: Type})}, {i: getOut, t: fnType({in: Function, out: Type})}, -]; +]}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..d76b85f --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@inquirer/prompts": "^7.4.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..e968e37 --- /dev/null +++ b/pnpm-lock.yaml @@ -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: {} diff --git a/primitives/bool.js b/primitives/bool.js index b5cdca9..5fbfb53 100644 --- a/primitives/bool.js +++ b/primitives/bool.js @@ -7,9 +7,9 @@ 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 = [ +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 }, -]; +]}; diff --git a/primitives/byte.js b/primitives/byte.js index 987ffd7..617a946 100644 --- a/primitives/byte.js +++ b/primitives/byte.js @@ -7,9 +7,9 @@ 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 = [ +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 }, -]; +]}; diff --git a/primitives/double.js b/primitives/double.js index defecdb..2ada9d1 100644 --- a/primitives/double.js +++ b/primitives/double.js @@ -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 ModuleDouble = [ +export const ModuleDouble = {l:[ {i: Double , t: Type }, {i: Double_to_Double_to_Double, t: Function }, @@ -24,4 +24,4 @@ export const ModuleDouble = [ {i: addDouble , t: Double_to_Double_to_Double }, {i: mulDouble , t: Double_to_Double_to_Double }, {i: eqDouble , t: Double_to_Double_to_Bool }, -]; +]}; diff --git a/primitives/int.js b/primitives/int.js index 391c1d3..2bdc8b9 100644 --- a/primitives/int.js +++ b/primitives/int.js @@ -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_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_to_Int_to_Int , t: Function }, @@ -24,4 +27,4 @@ export const ModuleInt = [ {i: addInt , t: Int_to_Int_to_Int }, {i: mulInt , t: Int_to_Int_to_Int }, {i: eqInt , t: Int_to_Int_to_Bool }, -]; +]}; diff --git a/progress.txt b/progress.txt new file mode 100644 index 0000000..60346f5 --- /dev/null +++ b/progress.txt @@ -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? + diff --git a/structures/list.js b/structures/list.js index f1d5e9c..53a7cc8 100644 --- a/structures/list.js +++ b/structures/list.js @@ -6,10 +6,10 @@ import { Module } from "./module.js"; const Type_to_Type = fnType({in: Type, out: Type}); const Type_to_Module = fnType({in: Type, out: Module}); -export const ModuleList = [ +export const ModuleList = {l:[ {i: lsType , t: Type_to_Type}, {i: Type_to_Type , t: Function}, {i: makeListModule, t: Type_to_Module}, {i: Type_to_Module, t: Function}, -]; +]}; diff --git a/structures/list_common.js b/structures/list_common.js index f1dbc45..742c776 100644 --- a/structures/list_common.js +++ b/structures/list_common.js @@ -50,20 +50,20 @@ export const makeListModule = elementType => { if (elementType === Byte) { // specialization: use Uint8Array instead of JS array - return [ + return {l:[ ...common, {i: byteListImpl.emptyList , t: ListOfElement}, {i: byteListImpl.get , t: getFnType}, {i: byteListImpl.put , t: putFnType}, - ]; + ]}; } else { - return [ + return {l:[ ...common, {i: emptyList , t: ListOfElement}, {i: get , t: getFnType}, {i: put , t: putFnType}, // {i: push , t: pushFnType}, - ]; + ]}; } }; diff --git a/structures/product.js b/structures/product.js index 9dfec02..5b98b48 100644 --- a/structures/product.js +++ b/structures/product.js @@ -16,7 +16,7 @@ export const makeProductType = (leftType, rightType) => { const constructorBoundType = fnType({in: rightType, out: pType}); const constructorType = fnType({in: leftType , out: constructorBoundType}); - return [ + return {l:[ {i: pType, t: Type}, {i: getLeft , t: leftFnType}, @@ -27,5 +27,5 @@ export const makeProductType = (leftType, rightType) => { {i: constructor , t: constructorType}, {i: constructorType , t: Function}, {i: constructorBoundType, t: Function}, - ]; + ]}; }; diff --git a/structures/sum.js b/structures/sum.js index 8d38982..686fe65 100644 --- a/structures/sum.js +++ b/structures/sum.js @@ -5,6 +5,8 @@ import { Module } from "./module.js"; const constructorLeft = left => ({variant: "L", value: left }); const constructorRight = right => ({variant: "R", value: right}); +// (, product(double, double)): product(int, type) + // signature: // sum-type -> (leftType -> resultType, rightType -> resultType) -> resultType 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 ); const matchFnType = fnType({in: sType, out: fnType({in: handlersType, out: returnType})}); - return [ + return {l:[ {i: match , t: matchFnType}, {i: matchFnType, t: Function}, - ]; + ]}; }; - return [ + return {l:[ {i: sType , t: Type}, {i: constructorLeft , t: constructorLeftType}, {i: constructorRight , t: constructorRightType}, @@ -40,5 +42,5 @@ export const makeSumType = (leftType, rightType) => { {i: constructorRightType, t: Function}, {i: makeMatchFn, t: fnType({in: Type, out: Module})}, - ]; + ]}; }; diff --git a/type_registry.js b/type_registry.js index 2d6b880..ad4de51 100644 --- a/type_registry.js +++ b/type_registry.js @@ -62,3 +62,19 @@ export const sumType = (leftType, rightType) => { 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; +// } +// } diff --git a/typed.js b/typed.js index d4b936e..a7ec80b 100644 --- a/typed.js +++ b/typed.js @@ -8,11 +8,11 @@ const getType = lnk => lnk.t; const Typed_to_Type = fnType({in: Typed, out: Type}); -export const ModuleTyped = [ +export const ModuleTyped = {l:[ {i: Typed, t: Type}, {i: Typed_to_Type, t: Function}, {i: getInst, t: Typed_to_Type}, {i: getType, t: Typed_to_Type}, -]; +]}; diff --git a/util.js b/util.js index 72d912b..9742612 100644 --- a/util.js +++ b/util.js @@ -40,3 +40,10 @@ export class DefaultMap { return this.m.entries(); } } + + +import { inspect } from 'node:util'; + +export function pretty(obj) { + return inspect(obj, {colors: true}); +} \ No newline at end of file