interactive prompt can handle polymorphic types

This commit is contained in:
Joeri Exelmans 2025-04-02 15:49:43 +02:00
parent a0e3aa0cb3
commit 4a4983f693
20 changed files with 485 additions and 276 deletions

View file

@ -1,13 +1,76 @@
import { Any } from "../typed.js";
import { String } from "./list.js";
import { sumType, prodType, fnType } from "./types.js";
import { SymbolT, Type } from "../primitives/types.js";
import { makeTypeConstructor } from "../type_constructor.js";
import { Module, String } from "./list.js";
import { prodType, fnType, lsType } from "./types.js";
function capitalizeFirstLetter(val) {
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
}
export const createNominalADT = symbol => variants => {
makeTypeConstructor(symbol, 0, )
export const createStruct = (typeVars, symbol, fields) => {
const makeConstructor = (remainingFields, obj={}) => {
if (remainingFields.length===0) {
return obj;
}
const {left: fieldName} = remainingFields[remainingFields.length-1];
return v => makeConstructor(
remainingFields.slice(0,-1),
Object.assign({[fieldName]: v}, obj));
};
const constructor = makeConstructor(fields);
const type = makeTypeConstructor(symbol)(typeVars.size);
const types = [ type ];
const recordFnType = inType => outType => {
const fnT = fnType(inType)(outType);
types.push(fnT);
return fnT;
}
const makeConstructorType = (remainingFields, type) => {
if (remainingFields.length===0) {
return type;
}
const {right: fieldType} = remainingFields[remainingFields.length-1];
return recordFnType(makeConstructorType(remainingFields.slice(0,-1)))(fieldType);
};
const constructorType = makeConstructorType(fields);
const functions = [
["constructor", constructor, constructorType],
...fields.map(({left: fieldName, right: fieldType}) => {
const getterName = 'get'+capitalizeFirstLetter(fieldName);
const getter = {
// stupid trick to give the JS-function a computed name.
// only important for debugging, so it says [Function: getAge] instead of [Function (anonymous)]:
[getterName]: obj => obj[fieldName],
}[getterName];
if (typeVars.has(fieldType)) {
// getterFnType = recordFnType(type)(fieldType)
}
const getterFnType = recordFnType(type)(fieldType);
return [fieldName, getter, getterFnType];
}),
];
const module = {l:[
{i: type, t: Type},
...functions.flatMap(([_, getter, getterFnType]) => [
{i: getter , t: getterFnType},
]),
...types.map(type => ({i: type, t: Type})),
]};
return {
module,
constructor,
functions: Object.fromEntries(functions),
};
};
export const createNominalADTFnType =
fnType
(Any)
();
export const createNominalADTModuleFnType =
fnType(SymbolT)
(fnType(lsType(prodType(String)(Type)))
(Module));