diff --git a/examples/environment.js b/examples/environment.js index 6ff41fa..6a741c8 100644 --- a/examples/environment.js +++ b/examples/environment.js @@ -1,27 +1,265 @@ -import { compareTypes } from "../lib/compare/type.js"; -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"; +import { number, select } from "@inquirer/prompts"; -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 setOfInstances = get(dict)(t) || emptySet(makeCompareFn(t)); return set(dict)(t)(add(setOfInstances)(i)); -} +}; -const typeDict = ModuleStd.reduce((typeDict, {i, t}) => { +const typeDict = foldList(typeDict => dynamic => { try { + const t = getType(dynamic); // add instance to type: return addEntry( - addEntry(typeDict)(i)(t) + addEntry(typeDict)(getInst(dynamic))(t) )(t)(Type); } catch (e) { - console.log('warning:',e.message); + console.log('warning:', e.message); 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)); diff --git a/examples/prompt.js b/examples/prompt.js deleted file mode 100644 index ef73ecb..0000000 --- a/examples/prompt.js +++ /dev/null @@ -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(); diff --git a/lib/generics/generics.js b/lib/generics/generics.js index e87cf31..df92250 100644 --- a/lib/generics/generics.js +++ b/lib/generics/generics.js @@ -1,7 +1,9 @@ +import { inspect } from "node:util"; import { eqType, getSymbol } from "../primitives/type.js"; import { zip } from "../util/util.js"; import { pretty, prettyT } from '../util/pretty.js'; import { isTypeVar, TYPE_VARS } from "../primitives/typevars.js"; +import { inspectType } from "../meta/type_constructor.js"; // helper for creating generic types // for instance, the type: @@ -150,6 +152,7 @@ const __unify = (fType, aType, fStack=[], aStack=[]) => { type: { symbol: fType.symbol, params: unifiedParams, + [inspect.custom]: inspectType, }, }; }; @@ -177,6 +180,7 @@ export const substitute = (type, substitutions, stack=[]) => { } return substitute(param, substitutions, [...stack, parent]); }), + [inspect.custom]: inspectType, }; }; diff --git a/lib/meta/type_constructor.js b/lib/meta/type_constructor.js index 90b1ba5..4edf048 100644 --- a/lib/meta/type_constructor.js +++ b/lib/meta/type_constructor.js @@ -2,11 +2,13 @@ import { getHumanReadableName } from "../primitives/symbol.js"; import { inspect } from "util"; import { prettyT } from "../util/pretty.js"; +export const inspectType = function(depth, options, inspect){ return options.stylize(prettyT(this), 'date'); } + const __makeTypeConstructor = (symbol, nAry, params) => { if (nAry === 0) { return { 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 diff --git a/lib/primitives/double.types.js b/lib/primitives/double.types.js index e0301a8..b13f3ba 100644 --- a/lib/primitives/double.types.js +++ b/lib/primitives/double.types.js @@ -6,6 +6,6 @@ const mkType = getDefaultTypeParser(); export const ModuleDouble = [ newDynamic(addDouble)(mkType("Double -> Double -> Double")), - newDynamic(mulDouble)(mkType("Double -> Double -> Double") ), - newDynamic(eqDouble)(mkType("Double -> Double -> Bool") ), + newDynamic(mulDouble)(mkType("Double -> Double -> Double")), + newDynamic(eqDouble )(mkType("Double -> Double -> Bool" )), ]; diff --git a/lib/primitives/dynamic.js b/lib/primitives/dynamic.js index 3ef2769..5316b2e 100644 --- a/lib/primitives/dynamic.js +++ b/lib/primitives/dynamic.js @@ -1,5 +1,6 @@ import { inspect } from "node:util"; import { assignFn } from "../generics/generics.js"; +import { select } from "@inquirer/prompts"; function inspectDynamic(_depth, options, inspect) { return `${inspect(this.i, options)} :: ${inspect(this.t, options)}`; diff --git a/lib/primitives/primitive_types.types.js b/lib/primitives/primitive_types.types.js index 936247a..74b87dc 100644 --- a/lib/primitives/primitive_types.types.js +++ b/lib/primitives/primitive_types.types.js @@ -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"; export const ModulePrimitiveSymbols = [ - newDynamic(SymbolInt )(UUID ), - newDynamic(SymbolBool )(UUID ), - newDynamic(SymbolDouble )(UUID ), - newDynamic(SymbolByte )(UUID ), - newDynamic(SymbolChar )(UUID ), - newDynamic(SymbolUnit )(UUID ), - newDynamic(SymbolBottom )(UUID ), - newDynamic(SymbolUUID )(UUID ), - newDynamic(SymbolType )(UUID ), - newDynamic(SymbolTop )(UUID ), - newDynamic(SymbolDynamic )(UUID ), + newDynamic(SymbolInt )(UUID), + newDynamic(SymbolBool )(UUID), + newDynamic(SymbolDouble )(UUID), + newDynamic(SymbolByte )(UUID), + newDynamic(SymbolChar )(UUID), + newDynamic(SymbolUnit )(UUID), + newDynamic(SymbolBottom )(UUID), + newDynamic(SymbolUUID )(UUID), + newDynamic(SymbolType )(UUID), + newDynamic(SymbolTop )(UUID), + newDynamic(SymbolDynamic)(UUID), ]; export const ModulePrimitiveTypes = [ - newDynamic(Int )(Type ), - newDynamic(Bool )(Type ), - newDynamic(Double )(Type ), - newDynamic(Byte )(Type ), - newDynamic(Char )(Type ), - newDynamic(Unit )(Type ), - newDynamic(Bottom )(Type ), - newDynamic(UUID )(Type ), - newDynamic(Type )(Type ), - newDynamic(Top )(Type ), - newDynamic(Dynamic )(Type ), + newDynamic(Int )(Type), + newDynamic(Bool )(Type), + newDynamic(Double )(Type), + newDynamic(Byte )(Type), + newDynamic(Char )(Type), + newDynamic(Unit )(Type), + newDynamic(Bottom )(Type), + newDynamic(UUID )(Type), + newDynamic(Type )(Type), + newDynamic(Top )(Type), + newDynamic(Dynamic)(Type), ]; diff --git a/lib/primitives/type.js b/lib/primitives/type.js index ad30b9d..ff1298c 100644 --- a/lib/primitives/type.js +++ b/lib/primitives/type.js @@ -3,4 +3,4 @@ import { compareTypes } from "../compare/type.js"; export const getSymbol = type => type.symbol; export const getParams = type => type.params; -export const eqType = t1 => t2 => compareTypes(t1, t2) === 0; +export const eqType = t1 => t2 => compareTypes(t1)(t2) === 0; diff --git a/lib/primitives/unit.js b/lib/primitives/unit.js index 01992fe..b4634e7 100644 --- a/lib/primitives/unit.js +++ b/lib/primitives/unit.js @@ -1,7 +1,3 @@ -import { inspect } from "node:util"; - -export const unit = { - [inspect.custom](depth, options, inspect){ return '()'; } -}; +export const unit = {}; export const eqUnit = _ => _ => true; diff --git a/lib/structures/dict.js b/lib/structures/dict.js index b614831..d43f0f7 100644 --- a/lib/structures/dict.js +++ b/lib/structures/dict.js @@ -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 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 last = dict => dict.tree.end; diff --git a/lib/structures/dict.types.js b/lib/structures/dict.types.js index cfab95c..11fd6ac 100644 --- a/lib/structures/dict.types.js +++ b/lib/structures/dict.types.js @@ -1,6 +1,6 @@ import { makeTypeParser } from "../parser/type_parser.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"; export const symbolDictIterator = 'DictIterator__d9d175b6bfd1283f00851a99787d0499'; @@ -13,12 +13,13 @@ const mkType = makeTypeParser({ }); export const ModuleDict = [ - newDynamic(emptyDict )(mkType("(a -> a -> Int) -> (a => b)") ), - newDynamic(has )(mkType("(a => b) -> a -> Bool")), - newDynamic(set )(mkType("(a => b) -> a -> b -> (a => b)")), - newDynamic(remove )(mkType("(a => b) -> a -> (a => b)")), - newDynamic(length )(mkType("(a => b) -> Int")), - 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(emptyDict)(mkType("(a -> a -> Int) -> (a => b) ")), + newDynamic(has )(mkType("(a => b) -> a -> Bool ")), + newDynamic(set )(mkType("(a => b) -> a -> b -> (a => b) ")), + newDynamic(remove )(mkType("(a => b) -> a -> (a => b) ")), + newDynamic(length )(mkType("(a => b) -> Int ")), + newDynamic(fold )(mkType("(c -> a -> b -> c) -> c -> (a => b) -> c ")), + newDynamic(first )(mkType("(a => b) -> (a |=>| b) ")), + newDynamic(last )(mkType("(a => b) -> (a |=>| b) ")), + newDynamic(read )(mkType("(a |=>| b) -> (Unit + ((a*b) * (a |=>| b)))")), ]; diff --git a/lib/structures/list.js b/lib/structures/list.js index 884a6da..d7bd7e1 100644 --- a/lib/structures/list.js +++ b/lib/structures/list.js @@ -7,7 +7,7 @@ export const push = ls => elem => ls.concat([elem]); export const pop = ls => ls.pop(); export const map = ls => fn => ls.map(elem => fn(elem)); export const length = ls => ls.length; -export const fold = ls => callback => initial => { +export const fold = callback => initial => ls => { let acc = initial; for (let i=0; i a")), newDynamic(map )(mkType("[a] -> (a -> b) -> [b]")), newDynamic(length )(mkType("[a] -> Int")), - newDynamic(fold )(mkType("[a] -> (b -> a -> b) -> b -> b")), + newDynamic(fold )(mkType("(b -> a -> b) -> b -> [a] -> b")), ]; diff --git a/lib/structures/set.js b/lib/structures/set.js index b39c513..0dda8ef 100644 --- a/lib/structures/set.js +++ b/lib/structures/set.js @@ -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 length = set => set.tree.length; -export const fold = set => callback => initial => { +export const fold = callback => initial => set => { let acc = initial; - let iter = set.tree.begin; - while (iter !== undefined && iter.valid) { - acc = callback(acc, iter.key); + for (const iter=set.tree.begin; iter !== undefined && iter.valid; iter.next()) { + acc = callback(acc)(iter.key); } return acc; }; diff --git a/lib/structures/set.types.js b/lib/structures/set.types.js index 1f02388..5e3556b 100644 --- a/lib/structures/set.types.js +++ b/lib/structures/set.types.js @@ -8,17 +8,18 @@ export const symbolSetIterator = 'SetIterator__f6b0ddd78ed41c58e5a442f2681da011' const setIterator = makeTypeConstructor(symbolSetIterator)(1); const mkType = makeTypeParser({ + // extra syntax to represent a set iterator: extraBracketOperators: [['<', ['>', setIterator]]], }); export const ModuleSet = [ - newDynamic(emptySet )(mkType("(a -> a -> Int) -> {a}") ), - newDynamic(has )(mkType("{a} -> a -> Bool")), - newDynamic(add )(mkType("{a} -> a -> {a}")), - newDynamic(remove )(mkType("{a} -> a -> {a}")), - newDynamic(length )(mkType("{a} -> Int")), - newDynamic(fold )(mkType("{a} -> (b -> a -> b) -> b")), - newDynamic(first )(mkType("{a} -> ")), - newDynamic(last )(mkType("{a} -> ")), - newDynamic(read )(mkType(" -> (Unit + (a * ))")), + newDynamic(emptySet)(mkType("(a -> a -> Int) -> {a}" )), + newDynamic(has )(mkType("{a} -> a -> Bool" )), + newDynamic(add )(mkType("{a} -> a -> {a}" )), + newDynamic(remove )(mkType("{a} -> a -> {a}" )), + newDynamic(length )(mkType("{a} -> Int" )), + newDynamic(fold )(mkType("(b -> a -> b) -> b -> {a} -> b")), + newDynamic(first )(mkType("{a} -> " )), + newDynamic(last )(mkType("{a} -> " )), + newDynamic(read )(mkType(" -> (Unit + (a * ))" )), ];