simplify: no distinction between generic types and 'normal' types.

This commit is contained in:
Joeri Exelmans 2025-05-08 16:58:07 +02:00
parent b4826605af
commit a664ddac8a
27 changed files with 535 additions and 360 deletions

View file

@ -11,7 +11,7 @@ const eatParameters = (numParams, result) => {
export const makeMatchFn = variants => {
if (variants.length === 0) {
return undefined;
throw new Error("Bottom!");
}
const [_, ...remainingVariants] = variants;
return sum => handler => {
@ -34,4 +34,4 @@ export const makeConstructors = variants => {
...makeConstructors(remainingVariants).map(ctor =>
({[ctor.name]: val => newRight(ctor(val))}[ctor.name])),
];
}
};

View file

@ -1,6 +1,10 @@
import { Bottom } from "../primitives/primitive_types.js";
import { makeCompareFn } from "../compare/dynamic.js";
import { makeGeneric } from "../generics/generics.js";
import { newDynamic } from "../primitives/dynamic.js";
import { Bottom, Type } from "../primitives/primitive_types.js";
import { makeConstructors, makeMatchFn } from "./enum.js";
import { getRight } from "./product.js";
import { sumType } from "./type_constructors.js";
import { fnType, sumType } from "./type_constructors.js";
// 'variants' is an array of (name: string, type: Type) pairs.
// e.g., the list of variants:
@ -10,11 +14,67 @@ import { sumType } from "./type_constructors.js";
// results in the type:
// (Int | ([Int] | (Unit | ⊥)))
export const enumType = variants => {
const _enumType = rootSelf => variants => {
// console.log("enumType..", variants);
if (variants.length === 0) {
return Bottom; // empty enum is equal to Bottom-type (cannot be instantiated)
}
const [variant, ...rest] = variants;
const variantType = getRight(variant);
return sumType(() => variantType)(() => enumType(rest));
return sumType
(self => {
// console.log("requested left type (of enumType)")
return variantType(rootSelf || self);
})
(self => {
// console.log("requested right type (of enumType)")
return _enumType(self)(rest)
});
};
export const enumType = _enumType(null);
export const makeConstructorTypes = type => variants => {
return variants.map(variant => {
const variantType = getRight(variant);
return fnType(_ => variantType)(_ => type);
});
}
export const makeMatchFnType = type => variants => {
return makeGeneric(resultType =>
fnType
(_ => type)
(_ => handlerType(resultType)(type)(variants)));
}
const handlerType = resultType => type => variants => {
if (variants.length === 0) {
return resultType;
}
const [variant, ...rest] = variants;
const variantType = getRight(variant);
return fnType
(_ => fnType(_ => variantType)(_ => resultType)), // handler
(_ => handlerType(resultType)(type)(rest)); // rest
}
export const makeModuleEnum = type => variants => {
const ctors = makeConstructors(variants);
const ctorTypes = makeConstructorTypes(type)(variants);
const matchFn = makeMatchFn(variants);
const matchFnType = makeMatchFnType(type)(variants);
const module = [
// newDynamic(type)(Type),
// constructors:
...zip(ctors, ctorTypes)
.map(([ctor, ctorType]) => newDynamic(ctor)(ctorType)),
// match-function:
newDynamic(matchFn, matchFnType),
// compare-function:
newDynamic(makeCompareFn(enumType(variants)))
];
}

View file

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

View file

@ -1,6 +1,6 @@
import { makeTypeParser } from "../parser/type_parser.js";
import { makeTypeConstructor } from "../meta/type_constructor.js";
import { emptySet, has, add, remove, length, first, read, last } from "./set.js";
import { emptySet, has, add, remove, length, first, read, last, fold } from "./set.js";
const setIterator = makeTypeConstructor('SetIterator__f6b0ddd78ed41c58e5a442f2681da011')(1);
@ -14,6 +14,7 @@ export const ModuleSet = [
{ 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} -> <a>")},
{ i: last , t: mkType("∀a: {a} -> <a>")},
{ i: read , t: mkType("∀a: <a> -> (Unit + (a * <a>))")},

View file

@ -13,40 +13,56 @@ import { fnType, prodType } from "./type_constructors.js";
// [{l: "x", r: Double}, {l: "y", r: Double}]
// results in the type (Double × (Double × Unit))
export const structType = fieldTypes => {
if (fieldTypes.length === 0) {
export const structType = (fields, rootSelf) => {
// console.log("structType..", fields);
if (fields.length === 0) {
return Unit;
}
const [fieldType, ...rest] = fieldTypes;
return prodType(_ => fieldType)(_ => structType(rest));
const [field, ...rest] = fields;
const fieldType = getRight(field);
return prodType
(self => {
// console.log("requested left type (of structType)")
return fieldType(rootSelf || self);
})
(self => {
// console.log("requested right type (of structType)")
return structType(rest, self);
});
};
export const makeConstructorType = fieldTypes => {
if (fieldTypes.length === 0) {
return structType(fieldTypes);
export const makeConstructorType = type => fields => {
if (fields.length === 0) {
return type;
// return structType(fields);
}
const [fieldType, ...rest] = fieldTypes;
return fnType(_ => fieldType)(_ => makeConstructorType(rest));
const [field, ...rest] = fields;
const fieldType = getRight(field);
return fnType(_ => fieldType)(_ => makeConstructorType(type, rest));
};
export const makeGettersTypes = fieldTypes => {
const type = structType(fieldTypes);
return fieldTypes.map(fieldType => {
export const makeGettersTypes = type => fields => {
// const type = structType(fields);
return fields.map(field => {
const fieldType = getRight(field);
return fnType(_ => type)(_ => fieldType);
});
};
export const makeModuleStruct = fields => {
export const makeModuleStruct = type => fields => {
const fieldNames = map(fields)(getLeft);
const fieldTypes = map(fields)(getRight);
const type = structType(fieldTypes);
// const type = structType(fields);
const ctor = makeConstructor(fields.length);
const ctorType = makeConstructorType(fieldTypes);
const getterTypes = makeGettersTypes(fieldTypes);
const ctorType = makeConstructorType(fields);
const getterTypes = makeGettersTypes(fields);
const getters = makeGetters(fieldNames);
const module = [
{i: type, t: Type},
// {i: type, t: Type},
// constructor
{i: ctor, t: ctorType},
// getters:
...zip(getters, getterTypes)
.map(([getter, getterType]) => newDynamic(getter)(getterType)),
];

View file

@ -1,16 +1,16 @@
import { getDefaultTypeParser } from "../parser/type_parser.js";
import { SymbolT } from "../primitives/primitive_types.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";
const mkType = getDefaultTypeParser();
export const ModuleStructuralSymbols = [
{ i: symbolSet , t: SymbolT },
{ i: symbolList , t: SymbolT },
{ i: symbolProduct , t: SymbolT },
{ i: symbolSum , t: SymbolT },
{ i: symbolDict , t: SymbolT },
{ i: symbolFunction , t: SymbolT },
{ i: symbolSet , t: UUID },
{ i: symbolList , t: UUID },
{ i: symbolProduct , t: UUID },
{ i: symbolSum , t: UUID },
{ i: symbolDict , t: UUID },
{ i: symbolFunction , t: UUID },
];
export const ModuleTypeConstructors = [