replace 'prompt' example by 'environment'

This commit is contained in:
Joeri Exelmans 2025-05-09 14:53:43 +02:00
parent f8008aa25d
commit b1c2e7836d
15 changed files with 317 additions and 517 deletions

View file

@ -1,27 +1,265 @@
import { compareTypes } from "../lib/compare/type.js"; import { number, select } from "@inquirer/prompts";
import { ModuleStd } from "../lib/stdlib.js";
import { emptyDict, get, set } from "../lib/structures/dict.js";
import { emptySet, add } from "../lib/structures/set.js";
import { makeCompareFn } from "../lib/compare/dynamic.js"
import { Type } from "../lib/primitives/primitive_types.js";
console.log(ModuleStd); import { makeCompareFn } from "../lib/compare/dynamic.js";
import { compareTypes } from "../lib/compare/type.js";
import { getInst, getType, newDynamic } from "../lib/primitives/dynamic.js";
import { Bool, Double, Int, Type, UUID } from "../lib/primitives/primitive_types.js";
import { eqType, getSymbol } from "../lib/primitives/type.js";
import { ModuleStd } from "../lib/stdlib.js";
import { emptyDict, get, set, fold as foldDict } from "../lib/structures/dict.js";
import { fold as foldList } from "../lib/structures/list.js";
import { add, emptySet, fold as foldSet } from "../lib/structures/set.js";
import { symbolFunction } from "../lib/structures/type_constructors.js";
import { pretty, prettyT } from "../lib/util/pretty.js";
import { genUUID } from "../lib/util/random.js";
import { assignFn, unify } from "../lib/generics/generics.js";
// console.log(ModuleStd);
const addEntry = dict => i => t => { const addEntry = dict => i => t => {
const setOfInstances = get(dict)(t) || emptySet(makeCompareFn(t)); const setOfInstances = get(dict)(t) || emptySet(makeCompareFn(t));
return set(dict)(t)(add(setOfInstances)(i)); return set(dict)(t)(add(setOfInstances)(i));
} };
const typeDict = ModuleStd.reduce((typeDict, {i, t}) => { const typeDict = foldList(typeDict => dynamic => {
try { try {
const t = getType(dynamic);
// add instance to type: // add instance to type:
return addEntry( return addEntry(
addEntry(typeDict)(i)(t) addEntry(typeDict)(getInst(dynamic))(t)
)(t)(Type); )(t)(Type);
} catch (e) { } catch (e) {
console.log('warning:',e.message); console.log('warning:', e.message);
return typeDict; return typeDict;
} }
}, emptyDict(compareTypes)); })(emptyDict(compareTypes))(ModuleStd);
console.log(typeDict); const functions = foldList(functions => dynamic => {
if (getSymbol(getType(dynamic)) === symbolFunction) {
return [...functions, dynamic];
}
return functions;
})([])(ModuleStd);
// console.log(typeDict);
// console.log(functions);
const defaultSelectOptions = {
pageSize: 20,
}
const selectInstance = async (type, msg) => {
const instances = get(typeDict)(type) || emptySet(makeCompareFn(type));
const choices = foldSet(acc => instance => {
return [...acc, {
value: instance,
name: pretty(instance),
}];
})(["(go back)", "(new)"])(instances);
const choice = await select({
message: `${msg} ${pretty(type)}:`,
choices,
...defaultSelectOptions,
});
if (choice === "(go back)") {
return;
}
if (choice === "(new)") {
return createInstance(type);
}
return choice;
}
const listInstances = async type => {
const choice = await selectInstance(type, "instances of");
if (choice === undefined) {
return;
}
await proxyDynamic(newDynamic(choice)(type));
return await listInstances(type);
}
const proxyDynamic = async dynamic => {
const type = getType(dynamic)
if (eqType(type)(Type)) {
return listTypeOptions(getInst(dynamic));
}
if (getSymbol(type) === symbolFunction) {
return listFunctionOptions(dynamic);
}
return listInstanceOptions(dynamic);
}
const listTypeOptions = async type => {
const choice = await select({
message: `type ${pretty(type)}:`,
choices: [
"(go back)",
"new",
"list instances",
"treat as instance",
],
});
if (choice === "(go back)") {
return;
}
if (choice === "new") {
const i = await createInstance(type);
if (i !== undefined) {
const dynamic = newDynamic(i)(type);
await proxyDynamic(dynamic);
}
}
if (choice === "list instances") {
await listInstances(type);
}
if (choice === "treat as instance") {
await listInstanceOptions(newDynamic(type)(Type));
}
return await listTypeOptions(type);
}
const listInstanceOptions = async dynamic => {
const choice = await select({
message: `instance ${pretty(dynamic)}:`,
choices: [
"(go back)",
"transform",
"get type",
],
});
if (choice === "(go back)") {
return;
}
if (choice === "transform") {
await transform(dynamic);
}
if (choice === "get type") {
await listTypeOptions(getType(dynamic));
}
return await listInstanceOptions(dynamic);
}
const listFunctionOptions = async dynamic => {
const choice = await select({
message: `function ${pretty(dynamic)}:`,
choices: [
"(go back)",
"call",
],
});
if (choice === "(go back)") {
return;
}
if (choice === "call") {
await call(dynamic);
}
}
const createInstance = async type => {
if (eqType(type)(Int)) {
const n = await number({
message: `enter an integer (leave empty to go back):`,
step: 1, // only integers
});
if (n === undefined) {
return;
}
return BigInt(n);
}
if (eqType(type)(Double)) {
const n = await number({
message: `enter a number (leave empty to go back):`,
step: 'any',
});
return n;
}
if (eqType(type)(Bool)) {
const b = await select({
message: `select:`,
choices: [
{value: false, name: 'false'},
{value: true, name: 'true'},
],
});
return b;
}
if (eqType(type)(UUID)) {
const descr = await input({message: "enter UUID description:"});
return descr + '__' + genUUID(16);
}
console.log("no prompt handler for creating new", prettyT(type));
};
const transform = async dynamic => {
const enabled = foldList(enabled => fun => {
try {
const outType = assignFn(getType(fun), getType(dynamic));
return [...enabled, {fun, outType}];
} catch (e) {
// console.log('warning:', e);
return enabled;
}
})([])(functions);
const choice = await select({
message: `select:`,
choices: [
"(go back)",
...enabled.map(({fun, outType}) => ({
value: {fun, outType},
name: `${getInst(fun).name} ${pretty(getInst(dynamic))} :: ${pretty(outType)}`,
})),
],
});
if (choice === "(go back)") {
return;
}
const {fun, outType} = choice;
const outValue = getInst(fun)(getInst(dynamic));
await proxyDynamic(newDynamic(outValue)(outType));
return transform(dynamic);
}
const call = async dynamic => {
const funType = getType(dynamic);
const allTypes = get(typeDict)(Type);
// compatible input types
const inTypes = foldSet(types => inType => {
try {
const outType = assignFn(funType, inType); // may throw
return [...types, {inType, outType}];
} catch (e) {
return types;
}
})([])(allTypes);
const choice = inTypes.length === 1
? inTypes[0]
: await select({
message: `types servable as input to ${pretty(funType)}:`,
choices: [
"(go back)",
...inTypes.map(({inType, outType}) => ({
value: {inType, outType},
name: pretty(inType),
})),
],
});
if (choice === "(go back)") {
return;
}
const inValue = await selectInstance(choice.inType, "select input value of type");
if (inValue === undefined) {
return;
}
const outValue = getInst(dynamic)(inValue);
await proxyDynamic(newDynamic(outValue)(choice.outType));
return call(dynamic);
}
await listInstances(Type);
// await transform(newDynamic(5)(Double));

View file

@ -1,449 +0,0 @@
import { select, number, input } from '@inquirer/prompts';
import { ModulePoint } from "../lib/point.js";
import { DefaultMap } from "../lib/util/defaultmap.js";
import { pretty } from '../lib/util/pretty.js';
import { isFunction } from '../structures/types.js';
import { ModuleStd } from '../lib/stdlib.js';
import { Double, GenericType, Int, UUID, Type } from "../primitives/types.js";
import { eqType } from '../primitives/type.js';
import { Top } from "../primitives/types.js";
import { assignFn, makeGeneric, onlyOccurring } from '../lib/generics/generics.js';
import { prettyT } from '../lib/util/pretty.js';
import { genUUID } from '../lib/util/random.js';
// import {emitKeypressEvents} from 'node:readline';
// // Configure readline to read from stdin
// emitKeypressEvents(process.stdin);
// process.stdin.setRawMode(true);
// console.log('Press any key (ESC to exit)...');
// process.stdin.on('keypress', (str, key) => {
// if (key.name === 'escape') {
// console.log('Escape key pressed!');
// process.exit();
// }
// });
const prettyIT = ({i, t}) => ({
strI: isType(i) ? prettyT(i) : pretty(i),
strT: prettyT(t),
// strI: pretty(i),
// strT: pretty(t),
});
const isType = i => i.typeVars || i.symbol;
// ctx.types.getdefault(i).has(Type)
// || ctx.types.getdefault(i).has(GenericType);
class Context {
constructor(mod) {
this.mod = mod;
this.types = new DefaultMap(() => new Set()); // instance to type
this.instances = new DefaultMap(() => new Set()); // type to instance
for (const {i, t} of mod.l) {
const {strI, strT} = prettyIT({i,t})
// console.log(strI, '::', strT);
this.types.getdefault(i, true).add(t);
this.types.getdefault(i, true).add(Top);
if (t.typeVars) {
// console.log("generic:", prettyT(t));
this.types.getdefault(t, true).add(GenericType);
}
else {
// console.log("non-generic:", prettyT(t));
this.types.getdefault(t, true).add(Type);
}
this.instances.getdefault(t, true).add(i);
this.instances.getdefault(Top, true).add(i);
}
const addIfFunctionType = (t, originalT, add) => {
if (isFunction(t)) {
for (const fn of this.instances.getdefault(originalT)) {
add(fn);
}
}
}
this.functions = [];
for (const type of this.instances.getdefault(Type)) {
addIfFunctionType(type, type, fn => this.functions.push({fn, type}));
}
this.genericFunctions = [];
for (const genericType of this.instances.getdefault(GenericType)) {
addIfFunctionType(genericType.type, genericType, fn => this.genericFunctions.push({fn, genericType}));
}
}
addToCtx({i, t}) {
return new Context({l:[
...this.mod.l,
{i, t},
]});
}
}
let ctx = new Context({l:[
...ModuleStd.l,
...ModulePoint.l,
]});
const toChoices = ([i, types]) => {
return [...types].map(t => {
const {strI, strT} = prettyIT({i, t});
return {
value: {i, t},
name: strI,
description: ` :: ${strT}`,
short: `${strI} :: ${strT}`,
};
});
};
async function topPrompt() {
const action = await select({
message: "What do you want to do?",
choices: [
"list all types",
"list all generic types",
"list all functions",
"list all",
],
});
if (action === "list all types") {
await listInstances(Type);
}
if (action === "list all generic types") {
await listInstances(GenericType);
}
if (action === "list all functions") {
await listAllFunctions();
}
if (action === "list all") {
await listAll();
}
return topPrompt();
}
async function listAllFunctions() {
const choice = await select({
message: "select function:",
choices: [
"(go back)",
...ctx.functions.flatMap(({fn, type}) => toChoices([fn, [type]])),
...ctx.genericFunctions.flatMap(({fn, genericType}) => toChoices([fn, [genericType]])),
],
});
if (choice === "(go back)") {
return;
}
const {i, t} = choice;
await functionOptions(i, t);
return listAllFunctions();
}
async function typeOptions(t, tt) {
const choice = await select({
message: `actions for type ${prettyT(t)} :: ${prettyT(tt)}`,
choices: [
"(go back)",
"create instance",
"list instances",
// "list outgoing functions",
// "list incoming functions",
"print raw",
"treat as instance",
],
});
if (choice === "(go back)") {
return;
}
else if (choice === "create instance") {
const i = await createInstance(t);
if (i !== undefined) {
ctx = ctx.addToCtx({i, t});
return instanceOrTypeOrFnOptions({i, t});
}
}
else if (choice === "list instances") {
await listInstances(t);
}
else if (choice === "print raw") {
console.log(pretty(t));
}
else if (choice === "treat as instance") {
await instanceOptions(t, tt)
}
else {
console.log("unimplemented:", choice);
}
return typeOptions(t, tt);
}
async function listAll() {
const choice = await select({
message: `all instances:`,
choices: [
"(go back)",
... [...ctx.types.m.keys()].flatMap(i => toChoices([i, ctx.types.getdefault(i)])),
],
})
if (choice === "(go back)") {
return;
}
return instanceOrTypeOrFnOptions(choice);
}
async function instanceOrTypeOrFnOptions({i, t}) {
if (t.typeVars) {
if (isFunction(t.type)) {
return functionOptions(i, t);
}
}
if (isFunction(t)) {
return functionOptions(i, t);
}
if (t === Type || t === GenericType) {
return typeOptions(i, t);
}
return instanceOptions(i,t);
}
async function listInstances(t) {
const choice = await select({
message: `instances of ${prettyT(t)}:`,
choices: [
"(go back)",
... [...ctx.instances.getdefault(t)].flatMap(i => toChoices([i, [t]])),
],
});
if (choice === "(go back)") {
return;
}
return instanceOrTypeOrFnOptions(choice);
}
async function listTypes(i) {
const {strI} = prettyIT({i,t:Type});
const choice = await select({
message: `type(s) of ${strI}:`,
choices: [
"(go back)",
... [...ctx.types.getdefault(i)].flatMap(t => toChoices([t, ctx.types.getdefault(t)])),
],
});
if (choice === "(go back)") {
return;
}
const {i: chosenType, t: typeOfChosenType} = choice;
await typeOptions(chosenType, typeOfChosenType);
return listTypes(i);
}
async function functionOptions(fn, fnT) {
const {strI, strT} = prettyIT({i: fn, t: fnT});
const choice = await select({
message: `actions for function ${strI} :: ${strT}`,
choices: [
"(go back)",
"call",
"treat as instance",
],
});
if (choice === "(go back)") {
return;
}
if (choice === "call") {
await callFunction(fn, fnT);
}
if (choice === "treat as instance") {
await instanceOptions(fn, fnT);
}
return functionOptions(fn, fnT);
}
async function createInstance(t) {
if (t.typeVars && t.typeVars.size === 0) {
t = t.type; // can treat as non-generic
}
if (eqType(t)(Int)) {
const n = await number({
message: `enter an integer (leave empty to go back):`,
step: 1, // only integers
});
if (n === undefined) {
return;
}
return BigInt(n);
}
else if (eqType(t)(Double)) {
const n = await number({
message: `enter a number (leave empty to go back):`,
step: 'any',
});
return n;
}
else if (eqType(t)(UUID)) {
console.log("Note: you are creating a new Symbol. Even if the description matches that of another symbol (e.g., \"Int\"), a new Symbol will be created that is unique and only equal to itself.");
const symbolDescr = await input({message: "enter symbol description:"});
return symbolDescr + '__' + genUUID(16);
}
else {
console.log("no prompt handler for creating new", prettyT(t));
}
}
async function callFunction(fn, fnT) {
const {strI, strT} = prettyIT({i: fn, t: fnT});
let choices;
let inType;
if (fnT.typeVars) {
// generic
choices = [...ctx.types.m.entries()].flatMap(([i, types]) => {
return [...types].flatMap(t => {
const genT = t.typeVars ? t : makeGeneric(() => t);
let assignedFnType;
try {
assignedFnType = assignFn(fnT, genT);
} catch (e) {
if (e.message.startsWith("cannot unify")) {
// console.warn(e);
return [];
}
throw e;
}
const assignedInType = onlyOccurring(assignedFnType.type.params[0], assignedFnType.typeVars);
if (assignedInType.typeVars.size > 0) {
return toChoices([i, [assignedInType]]);
}
else {
return toChoices([i, [assignedInType.type]]);
}
});
});
inType = onlyOccurring(fnT.type.params[0], fnT.typeVars)
}
else {
inType = fnT.params[0];
choices = [...ctx.instances.getdefault(inType)].flatMap(i => toChoices([i, [inType]]));
}
const choice = await select({
message: `select parameter of type ${prettyT(inType)} for function ${strI} :: ${strT}`,
choices: [
"(go back)",
"(new)",
...choices,
],
});
let i, t;
if (choice === "(go back)") {
return;
}
else if (choice === "(new)") {
i = await createInstance(inType);
t = inType;
if (i === undefined) {
return callFunction(fn, fnT);
}
}
else {
i = choice.i;
t = choice.t;
}
const genT = t.typeVars ? t : makeGeneric(() => t);
const genFnT = fnT.typeVars ? fnT : makeGeneric(() => fnT);
const assignedFnType = assignFn(genFnT, genT);
await apply(i, fn, assignedFnType);
return callFunction(fn, fnT);
}
async function instanceOptions(i,t) {
const {strI, strT} = prettyIT({i,t});
const choice = await select({
message: `actions for instance ${strI} :: ${strT}`,
choices: [
"(go back)",
"transform",
"list type(s)",
]
})
if (choice === "(go back)") {
return;
}
if (choice === "transform") {
await transform(i, t)
}
if (choice === "list type(s)") {
await listTypes(i);
}
return await instanceOptions(i,t);
}
async function transform(i, t) {
const {strI, strT} = prettyIT({i, t});
// console.log(ctx.functionsFrom.getdefault(t));
const genT = t.typeVars ? t : makeGeneric(() => t);
const choice = await select({
message: `choose transformation to perform on ${strI} :: ${strT}`,
choices: [
"(go back)",
...ctx.functions
.filter(({type}) => {
// console.log(type.params[0], t);
return eqType(type.params[0])(t)
})
.flatMap(({fn, type}) => toChoices([fn, [type]])),
...ctx.genericFunctions
.flatMap(({fn, genericType}) => {
let fnType;
try {
fnType = assignFn(genericType, genT);
} catch (e) {
if (e.message.startsWith("cannot unify")) {
// console.warn(e);
return [];
}
throw e;
}
return toChoices([fn, [fnType]]);
}),
],
});
if (choice === "(go back)") {
return;
}
const {i:fn,t:fnT} = choice;
await apply(i, fn, fnT);
return transform(i, t);
}
async function apply(i, fn, fnT) {
const result = fn(i);
let resultType;
if (fnT.typeVars) {
const res = onlyOccurring(fnT.type.params[1], fnT.typeVars);
resultType = res.typeVars.size > 0 ? res : res.type;
}
else {
resultType = fnT.params[1];
}
// update context with newly produced value
ctx = ctx
.addToCtx({i: result, t: resultType})
.addToCtx({i: resultType, t: resultType.typeVars ? GenericType : Type});
const {strI: strResult, strT: strResultType} = prettyIT({i: result, t: resultType});
console.log(`result = ${strResult} :: ${strResultType}`);
return instanceOrTypeOrFnOptions({i: result, t: resultType});
}
topPrompt();

View file

@ -1,7 +1,9 @@
import { inspect } from "node:util";
import { eqType, getSymbol } from "../primitives/type.js"; import { eqType, getSymbol } from "../primitives/type.js";
import { zip } from "../util/util.js"; import { zip } from "../util/util.js";
import { pretty, prettyT } from '../util/pretty.js'; import { pretty, prettyT } from '../util/pretty.js';
import { isTypeVar, TYPE_VARS } from "../primitives/typevars.js"; import { isTypeVar, TYPE_VARS } from "../primitives/typevars.js";
import { inspectType } from "../meta/type_constructor.js";
// helper for creating generic types // helper for creating generic types
// for instance, the type: // for instance, the type:
@ -150,6 +152,7 @@ const __unify = (fType, aType, fStack=[], aStack=[]) => {
type: { type: {
symbol: fType.symbol, symbol: fType.symbol,
params: unifiedParams, params: unifiedParams,
[inspect.custom]: inspectType,
}, },
}; };
}; };
@ -177,6 +180,7 @@ export const substitute = (type, substitutions, stack=[]) => {
} }
return substitute(param, substitutions, [...stack, parent]); return substitute(param, substitutions, [...stack, parent]);
}), }),
[inspect.custom]: inspectType,
}; };
}; };

View file

@ -2,11 +2,13 @@ import { getHumanReadableName } from "../primitives/symbol.js";
import { inspect } from "util"; import { inspect } from "util";
import { prettyT } from "../util/pretty.js"; import { prettyT } from "../util/pretty.js";
export const inspectType = function(depth, options, inspect){ return options.stylize(prettyT(this), 'date'); }
const __makeTypeConstructor = (symbol, nAry, params) => { const __makeTypeConstructor = (symbol, nAry, params) => {
if (nAry === 0) { if (nAry === 0) {
return { return {
symbol, params, symbol, params,
[inspect.custom](depth, options, inspect){ return options.stylize(prettyT(this), 'null'); }, [inspect.custom]: inspectType,
}; };
} }
// only for debugging, do we give the function a name // only for debugging, do we give the function a name

View file

@ -6,6 +6,6 @@ const mkType = getDefaultTypeParser();
export const ModuleDouble = [ export const ModuleDouble = [
newDynamic(addDouble)(mkType("Double -> Double -> Double")), newDynamic(addDouble)(mkType("Double -> Double -> Double")),
newDynamic(mulDouble)(mkType("Double -> Double -> Double") ), newDynamic(mulDouble)(mkType("Double -> Double -> Double")),
newDynamic(eqDouble)(mkType("Double -> Double -> Bool") ), newDynamic(eqDouble )(mkType("Double -> Double -> Bool" )),
]; ];

View file

@ -1,5 +1,6 @@
import { inspect } from "node:util"; import { inspect } from "node:util";
import { assignFn } from "../generics/generics.js"; import { assignFn } from "../generics/generics.js";
import { select } from "@inquirer/prompts";
function inspectDynamic(_depth, options, inspect) { function inspectDynamic(_depth, options, inspect) {
return `${inspect(this.i, options)} :: ${inspect(this.t, options)}`; return `${inspect(this.i, options)} :: ${inspect(this.t, options)}`;

View file

@ -2,29 +2,29 @@ import { newDynamic } from "./dynamic.js";
import { SymbolInt, UUID, SymbolBool, SymbolDouble, SymbolByte, SymbolChar, SymbolUnit, SymbolBottom, SymbolUUID, SymbolType, SymbolTop, Type, Int, Bool, Double, Byte, Char, Unit, Bottom, Top, SymbolDynamic, Dynamic } from "./primitive_types.js"; import { SymbolInt, UUID, SymbolBool, SymbolDouble, SymbolByte, SymbolChar, SymbolUnit, SymbolBottom, SymbolUUID, SymbolType, SymbolTop, Type, Int, Bool, Double, Byte, Char, Unit, Bottom, Top, SymbolDynamic, Dynamic } from "./primitive_types.js";
export const ModulePrimitiveSymbols = [ export const ModulePrimitiveSymbols = [
newDynamic(SymbolInt )(UUID ), newDynamic(SymbolInt )(UUID),
newDynamic(SymbolBool )(UUID ), newDynamic(SymbolBool )(UUID),
newDynamic(SymbolDouble )(UUID ), newDynamic(SymbolDouble )(UUID),
newDynamic(SymbolByte )(UUID ), newDynamic(SymbolByte )(UUID),
newDynamic(SymbolChar )(UUID ), newDynamic(SymbolChar )(UUID),
newDynamic(SymbolUnit )(UUID ), newDynamic(SymbolUnit )(UUID),
newDynamic(SymbolBottom )(UUID ), newDynamic(SymbolBottom )(UUID),
newDynamic(SymbolUUID )(UUID ), newDynamic(SymbolUUID )(UUID),
newDynamic(SymbolType )(UUID ), newDynamic(SymbolType )(UUID),
newDynamic(SymbolTop )(UUID ), newDynamic(SymbolTop )(UUID),
newDynamic(SymbolDynamic )(UUID ), newDynamic(SymbolDynamic)(UUID),
]; ];
export const ModulePrimitiveTypes = [ export const ModulePrimitiveTypes = [
newDynamic(Int )(Type ), newDynamic(Int )(Type),
newDynamic(Bool )(Type ), newDynamic(Bool )(Type),
newDynamic(Double )(Type ), newDynamic(Double )(Type),
newDynamic(Byte )(Type ), newDynamic(Byte )(Type),
newDynamic(Char )(Type ), newDynamic(Char )(Type),
newDynamic(Unit )(Type ), newDynamic(Unit )(Type),
newDynamic(Bottom )(Type ), newDynamic(Bottom )(Type),
newDynamic(UUID )(Type ), newDynamic(UUID )(Type),
newDynamic(Type )(Type ), newDynamic(Type )(Type),
newDynamic(Top )(Type ), newDynamic(Top )(Type),
newDynamic(Dynamic )(Type ), newDynamic(Dynamic)(Type),
]; ];

View file

@ -3,4 +3,4 @@ import { compareTypes } from "../compare/type.js";
export const getSymbol = type => type.symbol; export const getSymbol = type => type.symbol;
export const getParams = type => type.params; export const getParams = type => type.params;
export const eqType = t1 => t2 => compareTypes(t1, t2) === 0; export const eqType = t1 => t2 => compareTypes(t1)(t2) === 0;

View file

@ -1,7 +1,3 @@
import { inspect } from "node:util"; export const unit = {};
export const unit = {
[inspect.custom](depth, options, inspect){ return '()'; }
};
export const eqUnit = _ => _ => true; export const eqUnit = _ => _ => true;

View file

@ -18,6 +18,13 @@ export const set = dict => key => value => new RBTreeWrapper(dict.tree.remove(ke
export const remove = dict => key => new RBTreeWrapper(dict.tree.remove(key), inspectDict); export const remove = dict => key => new RBTreeWrapper(dict.tree.remove(key), inspectDict);
export const length = dict => dict.tree.length; export const length = dict => dict.tree.length;
export const fold = callback => initial => dict => {
let acc = initial;
for (const iter=dict.tree.begin; iter !== undefined && iter.valid; iter.next()) {
acc = callback(acc)(iter.key)(iter.value);
}
}
export const first = dict => dict.tree.begin; export const first = dict => dict.tree.begin;
export const last = dict => dict.tree.end; export const last = dict => dict.tree.end;

View file

@ -1,6 +1,6 @@
import { makeTypeParser } from "../parser/type_parser.js"; import { makeTypeParser } from "../parser/type_parser.js";
import { makeTypeConstructor } from "../meta/type_constructor.js"; import { makeTypeConstructor } from "../meta/type_constructor.js";
import { emptyDict, first, has, last, length, read, remove, set } from "./dict.js"; import { emptyDict, first, fold, has, last, length, read, remove, set } from "./dict.js";
import { newDynamic } from "../primitives/dynamic.js"; import { newDynamic } from "../primitives/dynamic.js";
export const symbolDictIterator = 'DictIterator__d9d175b6bfd1283f00851a99787d0499'; export const symbolDictIterator = 'DictIterator__d9d175b6bfd1283f00851a99787d0499';
@ -13,12 +13,13 @@ const mkType = makeTypeParser({
}); });
export const ModuleDict = [ export const ModuleDict = [
newDynamic(emptyDict )(mkType("(a -> a -> Int) -> (a => b)") ), newDynamic(emptyDict)(mkType("(a -> a -> Int) -> (a => b) ")),
newDynamic(has )(mkType("(a => b) -> a -> Bool")), newDynamic(has )(mkType("(a => b) -> a -> Bool ")),
newDynamic(set )(mkType("(a => b) -> a -> b -> (a => b)")), newDynamic(set )(mkType("(a => b) -> a -> b -> (a => b) ")),
newDynamic(remove )(mkType("(a => b) -> a -> (a => b)")), newDynamic(remove )(mkType("(a => b) -> a -> (a => b) ")),
newDynamic(length )(mkType("(a => b) -> Int")), newDynamic(length )(mkType("(a => b) -> Int ")),
newDynamic(first )(mkType("(a => b) -> (a |=>| b)")), newDynamic(fold )(mkType("(c -> a -> b -> c) -> c -> (a => b) -> c ")),
newDynamic(last )(mkType("(a => b) -> (a |=>| b)")), newDynamic(first )(mkType("(a => b) -> (a |=>| b) ")),
newDynamic(last )(mkType("(a => b) -> (a |=>| b) ")),
newDynamic(read )(mkType("(a |=>| b) -> (Unit + ((a*b) * (a |=>| b)))")), newDynamic(read )(mkType("(a |=>| b) -> (Unit + ((a*b) * (a |=>| b)))")),
]; ];

View file

@ -7,7 +7,7 @@ export const push = ls => elem => ls.concat([elem]);
export const pop = ls => ls.pop(); export const pop = ls => ls.pop();
export const map = ls => fn => ls.map(elem => fn(elem)); export const map = ls => fn => ls.map(elem => fn(elem));
export const length = ls => ls.length; export const length = ls => ls.length;
export const fold = ls => callback => initial => { export const fold = callback => initial => ls => {
let acc = initial; let acc = initial;
for (let i=0; i<ls.length; i++) { for (let i=0; i<ls.length; i++) {
acc = callback(acc)(ls[i]); acc = callback(acc)(ls[i]);

View file

@ -12,5 +12,5 @@ export const ModuleList = [
newDynamic(pop )(mkType("[a] -> a")), newDynamic(pop )(mkType("[a] -> a")),
newDynamic(map )(mkType("[a] -> (a -> b) -> [b]")), newDynamic(map )(mkType("[a] -> (a -> b) -> [b]")),
newDynamic(length )(mkType("[a] -> Int")), newDynamic(length )(mkType("[a] -> Int")),
newDynamic(fold )(mkType("[a] -> (b -> a -> b) -> b -> b")), newDynamic(fold )(mkType("(b -> a -> b) -> b -> [a] -> b")),
]; ];

View file

@ -19,11 +19,10 @@ export const add = set => key => set.tree.get(key) === true ? set : new RBTreeWr
export const remove = set => key => new RBTreeWrapper(set.tree.remove(key), inspectSet); export const remove = set => key => new RBTreeWrapper(set.tree.remove(key), inspectSet);
export const length = set => set.tree.length; export const length = set => set.tree.length;
export const fold = set => callback => initial => { export const fold = callback => initial => set => {
let acc = initial; let acc = initial;
let iter = set.tree.begin; for (const iter=set.tree.begin; iter !== undefined && iter.valid; iter.next()) {
while (iter !== undefined && iter.valid) { acc = callback(acc)(iter.key);
acc = callback(acc, iter.key);
} }
return acc; return acc;
}; };

View file

@ -8,17 +8,18 @@ export const symbolSetIterator = 'SetIterator__f6b0ddd78ed41c58e5a442f2681da011'
const setIterator = makeTypeConstructor(symbolSetIterator)(1); const setIterator = makeTypeConstructor(symbolSetIterator)(1);
const mkType = makeTypeParser({ const mkType = makeTypeParser({
// extra syntax to represent a set iterator:
extraBracketOperators: [['<', ['>', setIterator]]], extraBracketOperators: [['<', ['>', setIterator]]],
}); });
export const ModuleSet = [ export const ModuleSet = [
newDynamic(emptySet )(mkType("(a -> a -> Int) -> {a}") ), newDynamic(emptySet)(mkType("(a -> a -> Int) -> {a}" )),
newDynamic(has )(mkType("{a} -> a -> Bool")), newDynamic(has )(mkType("{a} -> a -> Bool" )),
newDynamic(add )(mkType("{a} -> a -> {a}")), newDynamic(add )(mkType("{a} -> a -> {a}" )),
newDynamic(remove )(mkType("{a} -> a -> {a}")), newDynamic(remove )(mkType("{a} -> a -> {a}" )),
newDynamic(length )(mkType("{a} -> Int")), newDynamic(length )(mkType("{a} -> Int" )),
newDynamic(fold )(mkType("{a} -> (b -> a -> b) -> b")), newDynamic(fold )(mkType("(b -> a -> b) -> b -> {a} -> b")),
newDynamic(first )(mkType("{a} -> <a>")), newDynamic(first )(mkType("{a} -> <a>" )),
newDynamic(last )(mkType("{a} -> <a>")), newDynamic(last )(mkType("{a} -> <a>" )),
newDynamic(read )(mkType("<a> -> (Unit + (a * <a>))")), newDynamic(read )(mkType("<a> -> (Unit + (a * <a>))" )),
]; ];