diff --git a/examples/environment.js b/examples/environment.js deleted file mode 100644 index d79748e..0000000 --- a/examples/environment.js +++ /dev/null @@ -1,19 +0,0 @@ -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" - -// console.log(ModuleStd); - -const typeDict = ModuleStd.reduce((typeDict, {i, t}) => { - try { - const instances = get(typeDict)(t) || emptySet(makeCompareFn(t)); - return set(typeDict)(t)(add(instances)(i)); - } catch (e) { - console.log('warning:',e.message); - return typeDict; - } -}, emptyDict(compareTypes)); - -console.log(typeDict); \ No newline at end of file diff --git a/examples/prompt.js b/examples/prompt.js index ef73ecb..7372296 100644 --- a/examples/prompt.js +++ b/examples/prompt.js @@ -4,7 +4,7 @@ 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 { Double, GenericType, Int, SymbolT, 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'; @@ -287,7 +287,7 @@ async function createInstance(t) { }); return n; } - else if (eqType(t)(UUID)) { + else if (eqType(t)(SymbolT)) { 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); diff --git a/lib/compare/dynamic.js b/lib/compare/dynamic.js index 6da7145..ef40f3c 100644 --- a/lib/compare/dynamic.js +++ b/lib/compare/dynamic.js @@ -1,8 +1,6 @@ import { getInst, getType } from "../primitives/dynamic.js"; import { SymbolBool, SymbolBottom, SymbolByte, SymbolChar, SymbolDouble, SymbolDynamic, SymbolInt, SymbolUUID, SymbolType, SymbolUnit } from "../primitives/primitive_types.js"; -import { UNBOUND_SYMBOLS } from "../primitives/typevars.js"; import { symbolDict, symbolFunction, symbolList, symbolProduct, symbolSet, symbolSum } from "../structures/type_constructors.js"; -import { prettyT } from "../util/pretty.js"; import { compareBools, compareNumbers, compareStrings, compareSymbols, compareUnits } from "./primitives.js"; import { compareDicts, compareFunctions, compareLists, compareProducts, compareSets, compareSums } from "./structures.js"; import { compareTypes } from "./type.js"; @@ -11,8 +9,6 @@ export const compareDynamic = x => y => compareTypes(getType(x))(getType(y)) || makeCompareFn(getType(x))(getInst(x))(getInst(y)); -const cannotCompareTypeVarInstances = _ => _ => { throw new Error("Cannot compare instance of type variables"); } - const typeSymbolToCmp = new Map([ [SymbolInt , compareNumbers], [SymbolBool , compareBools], @@ -21,7 +17,7 @@ const typeSymbolToCmp = new Map([ [SymbolChar , compareStrings], [SymbolUnit , compareUnits], [SymbolBottom , _ => _ => { throw new Error("Bottom!"); }], - [SymbolUUID , compareSymbols], + [SymbolUUID , compareSymbols], // [SymbolGenericType, ?] TODO [SymbolType , compareTypes], [SymbolDynamic, compareDynamic], @@ -33,20 +29,11 @@ const typeSymbolToCmp = new Map([ [symbolList , compareLists], [symbolSet , compareSets], [symbolDict , compareDicts], - - // even though we cannot compare typevar instances, - // we still need to give a function or shit will break - // types that contain typevars are never instantiated, - // EXCEPT: - // - generic functions (but for function comparison we don't look at the in/out types) - // - empty list, empty set, empty dict are all generic, but for each type there is only one empty element, so it never needs to be compared to another one - ...UNBOUND_SYMBOLS.map(uuid => [uuid, cannotCompareTypeVarInstances]), ]); export const makeCompareFn = type => { return type.params.reduce( (acc, cur) => acc(makeCompareFn(cur(type))), typeSymbolToCmp.get(type.symbol) - || (() => { throw new Error(`don't know how to compare instances of '${prettyT(type)}'`); })() ); }; diff --git a/lib/compare/dynamic.types.js b/lib/compare/dynamic.types.js index 157ef2d..c045093 100644 --- a/lib/compare/dynamic.types.js +++ b/lib/compare/dynamic.types.js @@ -4,6 +4,6 @@ import { compareDynamic, makeCompareFn } from "./dynamic.js"; const mkType = getDefaultTypeParser(); export const ModuleCompareDynamic = [ - {i: makeCompareFn , t: mkType("Type -> a -> a -> Int")}, + {i: makeCompareFn , t: mkType("∀a: Type -> a -> a -> Int")}, {i: compareDynamic, t: mkType("Dynamic -> Dynamic -> Int")}, ]; \ No newline at end of file diff --git a/lib/compare/primitives.types.js b/lib/compare/primitives.types.js index 77a92cd..c7a17fc 100644 --- a/lib/compare/primitives.types.js +++ b/lib/compare/primitives.types.js @@ -7,5 +7,5 @@ export const ModuleComparePrimitives = [ {i: compareNumbers, t: mkType("Double -> Double -> Int")}, {i: compareBools , t: mkType("Bool -> Bool -> Int")}, {i: compareUnits , t: mkType("Unit -> Unit -> Int")}, - {i: compareSymbols, t: mkType("UUID -> UUID -> Int")}, + {i: compareSymbols, t: mkType("SymbolT -> SymbolT -> Int")}, ]; diff --git a/lib/compare/structures.types.js b/lib/compare/structures.types.js index 199ae27..c5729d0 100644 --- a/lib/compare/structures.types.js +++ b/lib/compare/structures.types.js @@ -4,13 +4,13 @@ import { compareDicts, compareLists, compareProducts, compareSets, compareSums } const mkType = getDefaultTypeParser(); export const ModuleCompareStructures = [ - {i: compareLists, t: mkType("(a -> a -> Int) -> [a] -> [a] -> Int")}, + {i: compareLists, t: mkType("∀a: (a -> a -> Int) -> [a] -> [a] -> Int")}, - {i: compareProducts, t: mkType("(a -> a -> Int) -> (b -> b -> Int) -> (a*b) -> (a*b) -> Int")}, + {i: compareProducts, t: mkType("∀a,b: (a -> a -> Int) -> (b -> b -> Int) -> (a*b) -> (a*b) -> Int")}, - {i: compareSums, t: mkType("(a -> a -> Int) -> (b -> b -> Int) -> (a+b) -> (a+b) -> Int")}, + {i: compareSums, t: mkType("∀a,b: (a -> a -> Int) -> (b -> b -> Int) -> (a+b) -> (a+b) -> Int")}, - {i: compareSets, t: mkType("(a -> a -> Int) -> {a} -> {a} -> Int")}, + {i: compareSets, t: mkType("∀a: (a -> a -> Int) -> {a} -> {a} -> Int")}, - {i: compareDicts, t: mkType("(a -> a -> Int) -> (b -> b-> Int) -> (a => b) -> (a => b) -> Int")} + {i: compareDicts, t: mkType("∀a,b: (a -> a -> Int) -> (b -> b-> Int) -> (a => b) -> (a => b) -> Int")} ]; diff --git a/lib/generics/generics.js b/lib/generics/generics.js index e87cf31..37d3fbb 100644 --- a/lib/generics/generics.js +++ b/lib/generics/generics.js @@ -5,7 +5,7 @@ import { isTypeVar, TYPE_VARS } from "../primitives/typevars.js"; // helper for creating generic types // for instance, the type: -// a -> a -> Bool +// ∀a: a -> a -> Bool // is created by // makeGeneric(a => fnType(() => a)(() => fnType(() => a)(() => Bool))) export const makeGeneric = callback => { diff --git a/lib/meta/type_constructor.js b/lib/meta/type_constructor.js index 90b1ba5..825f76a 100644 --- a/lib/meta/type_constructor.js +++ b/lib/meta/type_constructor.js @@ -1,13 +1,8 @@ import { getHumanReadableName } from "../primitives/symbol.js"; -import { inspect } from "util"; -import { prettyT } from "../util/pretty.js"; const __makeTypeConstructor = (symbol, nAry, params) => { if (nAry === 0) { - return { - symbol, params, - [inspect.custom](depth, options, inspect){ return options.stylize(prettyT(this), 'null'); }, - }; + return { symbol, params }; } // only for debugging, do we give the function a name const fName = `${getHumanReadableName(symbol).toLowerCase()}Type${params.length>0?params.length:''}`; diff --git a/lib/meta/type_constructor.types.js b/lib/meta/type_constructor.types.js index c16b03f..ff13e94 100644 --- a/lib/meta/type_constructor.types.js +++ b/lib/meta/type_constructor.types.js @@ -5,5 +5,5 @@ const mkType = getDefaultTypeParser(); export const ModuleTypeConstructor = [ // Problem: number of parameters of returned function depends on the 'Int' parameter... - // {i: makeTypeConstructor, t: mkType("UUID -> Int -> ??")} + // {i: makeTypeConstructor, t: mkType("SymbolT -> Int -> ??")} ]; diff --git a/lib/parser/type_parser.js b/lib/parser/type_parser.js index 0a35c45..9378f1f 100644 --- a/lib/parser/type_parser.js +++ b/lib/parser/type_parser.js @@ -5,13 +5,8 @@ import { Dynamic } from "../primitives/primitive_types.js"; import { getHumanReadableName } from "../primitives/symbol.js"; import { getSymbol } from "../primitives/type.js"; import { TYPE_VARS } from "../primitives/typevars.js"; -import { dictType, fnType, lsType, prodType, sumType } from "../structures/type_constructors.types.js"; -import { setType } from "../structures/type_constructors.types.js"; - -// A very stupid little parser, that can only parse: -// - primitives => simply maps onto types. -// - things between brackets => calls a type constructor that takes one parameter on whatever is between the brackets. -// - binary (infix) operators => calls a type constructor that takes two parameters on the LHS and RHS. +import { dictType, fnType, lsType, prodType, sumType } from "../structures/type_constructors.js"; +import { setType } from "../structures/type_constructors.js"; export const makeTypeParser = ({ // parser can be extended: @@ -54,6 +49,13 @@ export const makeTypeParser = ({ ['⇒', dictType], ['=>', dictType], + // only used for type variables (e.g., ∀a,b,c:) + [',', fnX => fnY => { + const x = fnX(); + const y = fnY(); + return Array.isArray(x) ? x.concat(y) : [x].concat(y) + }], + ...extraInfixOperators, ]); diff --git a/lib/primitives/dynamic.js b/lib/primitives/dynamic.js index e00e67e..6f01125 100644 --- a/lib/primitives/dynamic.js +++ b/lib/primitives/dynamic.js @@ -1,18 +1,3 @@ -import { assignFn } from "../generics/generics.js"; - export const newDynamic = i => t => ({i, t}); - export const getInst = lnk => lnk.i; export const getType = lnk => lnk.t; - -export const apply = input => fun => { - const inputType = getType(input) - const funType = getType(fun); - const outputType = assignFn(funType, inputType); - - const inputValue = getInst(input); - const funValue = getInst(fun); - const outputValue = funValue(inputValue); - - return newDynamic(outputValue, outputType); -}; diff --git a/lib/primitives/dynamic.types.js b/lib/primitives/dynamic.types.js index c36af30..1cf645a 100644 --- a/lib/primitives/dynamic.types.js +++ b/lib/primitives/dynamic.types.js @@ -1,16 +1,14 @@ import { getDefaultTypeParser } from "../parser/type_parser.js"; -import { apply, getInst, getType, newDynamic } from "./dynamic.js"; +import { getInst, getType, newDynamic } from "./dynamic.js"; const mkType = getDefaultTypeParser(); export const ModuleDynamic = [ - { i: newDynamic, t: mkType("a -> Type -> Dynamic")}, + { i: newDynamic, t: mkType("∀a: a -> Type -> Dynamic")}, // allows us to (unsafely) cast the result to the specific type... // (not sure if this is the right way to go) - { i: getInst, t: mkType("Dynamic -> a") }, + { i: getInst, t: mkType("∀a: Dynamic -> a") }, { i: getType, t: mkType("Dynamic -> Type") }, - - { i: apply, t: mkType("Dynamic -> Dynamic -> Dynamic") }, ]; diff --git a/lib/primitives/symbol.types.js b/lib/primitives/symbol.types.js index 31453c2..04f74a3 100644 --- a/lib/primitives/symbol.types.js +++ b/lib/primitives/symbol.types.js @@ -4,6 +4,6 @@ import { eqSymbol, getHumanReadableName } from "./symbol.js"; const mkType = getDefaultTypeParser(); export const ModuleSymbol = [ - { i: getHumanReadableName, t: mkType("UUID -> String")}, - { i: eqSymbol, t: mkType("UUID -> UUID -> Bool")}, + { i: getHumanReadableName, t: mkType("SymbolT -> String")}, + { i: eqSymbol, t: mkType("SymbolT -> SymbolT -> Bool")}, ]; diff --git a/lib/primitives/type.types.js b/lib/primitives/type.types.js index a840c79..52992a0 100644 --- a/lib/primitives/type.types.js +++ b/lib/primitives/type.types.js @@ -8,6 +8,6 @@ const mkType = getDefaultTypeParser(); // each 'typed object' is implicitly an instance of TypeLink (defined below) export const ModuleType = [ {i: eqType , t: mkType("Type -> Type -> Bool")}, - {i: getSymbol, t: mkType("Type -> UUID")}, + {i: getSymbol, t: mkType("Type -> SymbolT")}, {i: getParams, t: mkType("Type -> [Type -> Type]")}, ]; 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..94b0860 100644 --- a/lib/structures/dict.js +++ b/lib/structures/dict.js @@ -1,21 +1,12 @@ import { RBTreeWrapper } from "../util/rbtree_wrapper.js"; -import { indent } from "../util/util.js"; import { newProduct } from "./product.js"; import { newLeft, newRight } from "./sum.js"; -// only for debugging -function inspectDict(_depth, options, inspect) { - const entries = []; - this.tree.forEach((key, val) => { entries.push(`${inspect(key, options)} => ${inspect(val, options)}`); }); - return `{\n${indent(entries.join(',\n'),2)}\n}`; -} +export const emptyDict = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y)); -export const emptyDict = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y), inspectDict); - -export const has = dict => key => dict.tree.get(key) !== undefined; -export const get = dict => key => dict.tree.get(key); -export const set = dict => key => value => new RBTreeWrapper(dict.tree.remove(key).insert(key, value), inspectDict); -export const remove = dict => key => new RBTreeWrapper(dict.tree.remove(key), inspectDict); +export const has = dict => key => dict.tree.get(key) === true; +export const set = dict => key => value => new RBTreeWrapper(dict.tree.remove(key).insert(key, value)); +export const remove = dict => key => new RBTreeWrapper(dict.tree.remove(key)); export const length = dict => dict.tree.length; export const first = dict => dict.tree.begin; diff --git a/lib/structures/dict.types.js b/lib/structures/dict.types.js index c27ff43..3b2e7bc 100644 --- a/lib/structures/dict.types.js +++ b/lib/structures/dict.types.js @@ -2,22 +2,19 @@ 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"; -export const symbolDictIterator = 'DictIterator__d9d175b6bfd1283f00851a99787d0499'; - -const dictIterator = makeTypeConstructor(symbolDictIterator)(2); +const dictIterator = makeTypeConstructor('DictIterator__d9d175b6bfd1283f00851a99787d0499')(2); const mkType = makeTypeParser({ - // we invent a bit of syntax for the dict iterator type, which takes two type parameters (key and value) extraInfixOperators: [['|=>|', dictIterator]], }); export const ModuleDict = [ - { i: emptyDict , t: mkType("(a -> a -> Int) -> (a => b)") }, - { i: has , t: mkType("(a => b) -> a -> Bool")}, - { i: set , t: mkType("(a => b) -> a -> b -> (a => b)")}, - { i: remove , t: mkType("(a => b) -> a -> (a => b)")}, - { i: length , t: mkType("(a => b) -> Int")}, - { i: first , t: mkType("(a => b) -> (a |=>| b)")}, - { i: last , t: mkType("(a => b) -> (a |=>| b)")}, - { i: read , t: mkType("(a |=>| b) -> (Unit + ((a*b) * (a |=>| b)))")}, + { i: emptyDict , t: mkType("∀a,b: (a -> a -> Int) -> (a => b)") }, + { i: has , t: mkType("∀a,b: (a => b) -> a -> Bool")}, + { i: set , t: mkType("∀a,b: (a => b) -> a -> b -> (a => b)")}, + { i: remove , t: mkType("∀a,b: (a => b) -> a -> (a => b)")}, + { i: length , t: mkType("∀a,b: (a => b) -> Int")}, + { i: first , t: mkType("∀a,b: (a => b) -> (a |=>| b)")}, + { i: last , t: mkType("∀a,b: (a => b) -> (a |=>| b)")}, + { i: read , t: mkType("∀a,b: (a |=>| b) -> (Unit + ((a*b) * (a |=>| b)))")}, ]; diff --git a/lib/structures/list.types.js b/lib/structures/list.types.js index 8801276..b3fa8f3 100644 --- a/lib/structures/list.types.js +++ b/lib/structures/list.types.js @@ -4,12 +4,12 @@ import { emptyList, fold, get, length, map, pop, push, put } from "./list.js"; const mkType = getDefaultTypeParser(); export const ModuleList = [ - { i: emptyList, t: mkType("[a]")}, - { i: get , t: mkType("[a] -> Int -> a")}, - { i: put , t: mkType("[a] -> Int -> a -> [a]")}, - { i: push , t: mkType("[a] -> a -> [a]")}, - { i: pop , t: mkType("[a] -> a")}, - { i: map , t: mkType("[a] -> (a -> b) -> [b]")}, - { i: length , t: mkType("[a] -> Int")}, - { i: fold , t: mkType("[a] -> (b -> a -> b) -> b -> b")}, + { i: emptyList, t: mkType("∀a: [a]")}, + { i: get , t: mkType("∀a: [a] -> Int -> a")}, + { i: put , t: mkType("∀a: [a] -> Int -> a -> [a]")}, + { i: push , t: mkType("∀a: [a] -> a -> [a]")}, + { i: pop , t: mkType("∀a: [a] -> a")}, + { i: map , t: mkType("∀a: [a] -> (a -> b) -> [b]")}, + { i: length , t: mkType("∀a: [a] -> Int")}, + { i: fold , t: mkType("∀a: [a] -> (b -> a -> b) -> b -> b")}, ]; diff --git a/lib/structures/product.types.js b/lib/structures/product.types.js index 3e44a99..47b3c13 100644 --- a/lib/structures/product.types.js +++ b/lib/structures/product.types.js @@ -4,7 +4,7 @@ import { newProduct, getLeft, getRight } from "./product.js"; const mkType = getDefaultTypeParser(); export const ModuleProduct = [ - { i: newProduct, t: mkType("a -> b -> (a * b)") }, - { i: getLeft , t: mkType("(a * b) -> a" ) }, - { i: getRight , t: mkType("(a * b) -> b" ) }, + { i: newProduct, t: mkType("∀a,b: a -> b -> (a * b)") }, + { i: getLeft , t: mkType("∀a,b: (a * b) -> a" ) }, + { i: getRight , t: mkType("∀a,b: (a * b) -> b" ) }, ]; diff --git a/lib/structures/set.js b/lib/structures/set.js index b39c513..a535de6 100644 --- a/lib/structures/set.js +++ b/lib/structures/set.js @@ -2,21 +2,13 @@ import { newRight } from "./sum.js"; import { newProduct } from "./product.js"; import { unit } from "../primitives/unit.js"; import { RBTreeWrapper } from "../util/rbtree_wrapper.js"; -import { indent } from "../util/util.js"; - -// only for debugging -function inspectSet(_depth, options, inspect) { - const keys = []; - this.tree.forEach((key) => { keys.push(inspect(key, options)); }); - return `{\n${indent(keys.join(',\n'), 2)}\n}`; -} // (a -> a -> Int) -> Set(a) -export const emptySet = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y), inspectSet); +export const emptySet = compareFn => RBTreeWrapper.new((x, y) => compareFn(x)(y)); export const has = set => key => set.tree.get(key) === true; -export const add = set => key => set.tree.get(key) === true ? set : new RBTreeWrapper(set.tree.insert(key, true), inspectSet); -export const remove = set => key => new RBTreeWrapper(set.tree.remove(key), inspectSet); +export const add = set => key => set.tree.get(key) === true ? set : new RBTreeWrapper(set.tree.insert(key, true)); +export const remove = set => key => new RBTreeWrapper(set.tree.remove(key)); export const length = set => set.tree.length; export const fold = set => callback => initial => { diff --git a/lib/structures/set.types.js b/lib/structures/set.types.js index 82827a8..32fe7af 100644 --- a/lib/structures/set.types.js +++ b/lib/structures/set.types.js @@ -2,22 +2,20 @@ import { makeTypeParser } from "../parser/type_parser.js"; import { makeTypeConstructor } from "../meta/type_constructor.js"; import { emptySet, has, add, remove, length, first, read, last, fold } from "./set.js"; -export const symbolSetIterator = 'SetIterator__f6b0ddd78ed41c58e5a442f2681da011'; - -const setIterator = makeTypeConstructor(symbolSetIterator)(1); +const setIterator = makeTypeConstructor('SetIterator__f6b0ddd78ed41c58e5a442f2681da011')(1); const mkType = makeTypeParser({ extraBracketOperators: [['<', ['>', setIterator]]], }); export const ModuleSet = [ - { i: emptySet , t: mkType("(a -> a -> Int) -> {a}") }, - { i: has , t: mkType("{a} -> a -> Bool")}, - { i: add , t: mkType("{a} -> a -> {a}")}, - { i: remove , t: mkType("{a} -> a -> {a}")}, - { i: length , t: mkType("{a} -> Int")}, - { i: fold , t: mkType("{a} -> (b -> a -> b) -> b")}, - { i: first , t: mkType("{a} -> ")}, - { i: last , t: mkType("{a} -> ")}, - { i: read , t: mkType(" -> (Unit + (a * ))")}, + { i: emptySet , t: mkType("∀a: (a -> a -> Int) -> {a}") }, + { i: has , t: mkType("∀a: {a} -> a -> Bool")}, + { i: add , t: mkType("∀a: {a} -> a -> {a}")}, + { i: remove , t: mkType("∀a: {a} -> a -> {a}")}, + { i: length , t: mkType("∀a: {a} -> Int")}, + { i: fold , t: mkType("∀a,b: {a} -> (b -> a -> b) -> b")}, + { i: first , t: mkType("∀a: {a} -> ")}, + { i: last , t: mkType("∀a: {a} -> ")}, + { i: read , t: mkType("∀a: -> (Unit + (a * ))")}, ]; diff --git a/lib/structures/sum.types.js b/lib/structures/sum.types.js index 38741e0..b9a8b20 100644 --- a/lib/structures/sum.types.js +++ b/lib/structures/sum.types.js @@ -4,7 +4,7 @@ import { match, newLeft, newRight } from "./sum.js"; const mkType = getDefaultTypeParser(); export const ModuleSum = [ - { i: newLeft , t: mkType("a -> (a + b)") }, - { i: newRight , t: mkType("b -> (a + b)") }, - { i: match , t: mkType("(a + b) -> (a -> c) -> (b -> c) -> c") }, + { i: newLeft , t: mkType("∀a,b: a -> (a + b)") }, + { i: newRight , t: mkType("∀a,b: b -> (a + b)") }, + { i: match , t: mkType("∀a,b,c: (a + b) -> (a -> c) -> (b -> c) -> c") }, ]; diff --git a/lib/structures/type_constructors.js b/lib/structures/type_constructors.js index 77c834c..0ec9b65 100644 --- a/lib/structures/type_constructors.js +++ b/lib/structures/type_constructors.js @@ -1,8 +1,17 @@ // to break up dependency cycles, type constructors are defined in their own JS module +import { makeTypeConstructor } from "../meta/type_constructor.js"; + export const symbolFunction = "Function__c2433e31fa574a2cb3b6b5d62ac9d4b2"; export const symbolSum = "Sum__89b731efa6344ea0b6a8663a45cf3ea8"; export const symbolProduct = "Product__89351ecdedfb4b05b2a5a6cc0c383e12"; export const symbolList = "List__daa8de8a9047435e96034ec64f2da3a1"; export const symbolSet = "Set__8fef2c1873df4327ac31bd61d2ecf7e0"; export const symbolDict = "Dict__d7158547322549ac9f7f8176aec123dd"; + +export const fnType = makeTypeConstructor(symbolFunction)(2); +export const sumType = makeTypeConstructor(symbolSum)(2); +export const prodType = makeTypeConstructor(symbolProduct)(2); +export const lsType = makeTypeConstructor(symbolList)(1); +export const setType = makeTypeConstructor(symbolSet)(1); +export const dictType = makeTypeConstructor(symbolDict)(2); diff --git a/lib/structures/type_constructors.types.js b/lib/structures/type_constructors.types.js index d0acf22..81d2c03 100644 --- a/lib/structures/type_constructors.types.js +++ b/lib/structures/type_constructors.types.js @@ -1,13 +1,8 @@ -import { makeTypeConstructor } from "../meta/type_constructor.js"; -import { Type, UUID } from "../primitives/primitive_types.js"; -import { symbolDict, symbolFunction, symbolList, symbolProduct, symbolSet, symbolSum } from "./type_constructors.js"; +import { getDefaultTypeParser } from "../parser/type_parser.js"; +import { UUID } from "../primitives/primitive_types.js"; +import { dictType, fnType, lsType, prodType, setType, sumType, symbolDict, symbolFunction, symbolList, symbolProduct, symbolSet, symbolSum } from "./type_constructors.js"; -export const fnType = makeTypeConstructor(symbolFunction)(2); -export const sumType = makeTypeConstructor(symbolSum)(2); -export const prodType = makeTypeConstructor(symbolProduct)(2); -export const lsType = makeTypeConstructor(symbolList)(1); -export const setType = makeTypeConstructor(symbolSet)(1); -export const dictType = makeTypeConstructor(symbolDict)(2); +const mkType = getDefaultTypeParser(); export const ModuleStructuralSymbols = [ { i: symbolSet , t: UUID }, @@ -18,15 +13,11 @@ export const ModuleStructuralSymbols = [ { i: symbolFunction , t: UUID }, ]; -const unaryTypeConstructor = fnType(_ => Type)(_ => Type); - -const binaryTypeConstructor = fnType(_ => Type)(_ => unaryTypeConstructor); - export const ModuleTypeConstructors = [ - { i: setType , t: unaryTypeConstructor }, - { i: lsType , t: unaryTypeConstructor }, - { i: prodType , t: binaryTypeConstructor }, - { i: sumType , t: binaryTypeConstructor }, - { i: dictType , t: binaryTypeConstructor }, - { i: fnType , t: binaryTypeConstructor }, -]; + { i: setType , t: mkType("Type -> Type") }, + { i: lsType , t: mkType("Type -> Type") }, + { i: prodType , t: mkType("Type -> Type -> Type") }, + { i: sumType , t: mkType("Type -> Type -> Type") }, + { i: dictType , t: mkType("Type -> Type -> Type") }, + { i: fnType , t: mkType("Type -> Type -> Type") }, +]; \ No newline at end of file diff --git a/lib/util/pretty.js b/lib/util/pretty.js index 9e566e5..a1d0d1f 100644 --- a/lib/util/pretty.js +++ b/lib/util/pretty.js @@ -1,5 +1,6 @@ import { inspect } from 'node:util'; -import { symbolDict, symbolFunction, symbolList, symbolProduct, symbolSum, symbolSet } from '../structures/type_constructors.js'; +import { symbolDict, symbolFunction, symbolList, symbolProduct, symbolSum } from '../structures/type_constructors.js'; +import { symbolSet } from "../structures/type_constructors.js"; import { getHumanReadableName } from '../primitives/symbol.js'; import { getSymbol } from '../primitives/type.js'; diff --git a/lib/util/rbtree_wrapper.js b/lib/util/rbtree_wrapper.js index dc5d067..51f34e5 100644 --- a/lib/util/rbtree_wrapper.js +++ b/lib/util/rbtree_wrapper.js @@ -3,19 +3,19 @@ import createRBTree from "functional-red-black-tree"; import { inspect } from "util"; -function defaultPrintf(depth, options, inspect) { - const entries = []; - this.tree.forEach((key, val) => { entries.push(`${inspect(key)} => ${inspect(val)}`); }); - return `RBTree(${this.tree.length}) {${entries.join(', ')}}`; -} - export class RBTreeWrapper { - constructor(tree, printf = defaultPrintf) { + constructor(tree) { this.tree = tree; - this[inspect.custom] = printf; } static new(compareFn) { return new RBTreeWrapper(createRBTree(compareFn)) } + + // pretty print to console + [inspect.custom](depth, options, inspect) { + const entries = []; + this.tree.forEach((key, val) => { entries.push(`${inspect(key)} => ${inspect(val)}`); }); + return `RBTree(${this.tree.length}) {${entries.join(', ')}}`; + } } diff --git a/lib/util/util.js b/lib/util/util.js index d993bbd..9bbd332 100644 --- a/lib/util/util.js +++ b/lib/util/util.js @@ -18,7 +18,3 @@ export const memoize = callback => { return result; }; }; - -export const indent = (multiline, n) => { - return multiline.split('\n').map(line => ' '.repeat(n)+line).join('\n'); -} \ No newline at end of file diff --git a/tests/recursive_types.js b/tests/recursive_types.js index 06f204f..407839c 100644 --- a/tests/recursive_types.js +++ b/tests/recursive_types.js @@ -3,7 +3,7 @@ import { compareTypes } from "../lib/compare/type.js"; import { makeGeneric, substitute, unify } from "../lib/generics/generics.js"; import { Double, Int, Unit } from "../lib/primitives/primitive_types.js"; import { UNBOUND_SYMBOLS } from "../lib/primitives/typevars.js"; -import { fnType, lsType, prodType, sumType, setType } from "../lib/structures/type_constructors.types.js"; +import { fnType, lsType, prodType, sumType, setType } from "../lib/structures/type_constructors.js"; import { prettyT } from "../lib/util/pretty.js"; // some recursive types: