export __unify

This commit is contained in:
Joeri Exelmans 2025-05-18 09:38:30 +02:00
parent 0096bb5559
commit 8266e59b94

View file

@ -88,7 +88,7 @@ export class NotAFunctionError extends Error {}
// typeVars: all the type variables in both fType and aType // typeVars: all the type variables in both fType and aType
// fType, aType: generic types to unify // fType, aType: generic types to unify
// fStack, aStack: internal use. // fStack, aStack: internal use.
const __unify = (fType, aType, fStack=[], aStack=[]) => { export const __unify = (fType, aType, fStack=[], aStack=[]) => {
// console.log("__unify", {typeVars, fType: prettyT(fType), aType: prettyT(aType), fStack, aStack}); // console.log("__unify", {typeVars, fType: prettyT(fType), aType: prettyT(aType), fStack, aStack});
if (isTypeVar(fType)) { if (isTypeVar(fType)) {
// simplest case: formalType is a type paramater // simplest case: formalType is a type paramater
@ -196,18 +196,22 @@ export const assignFnSubstitutions = (funType, paramType) => {
if (getSymbol(funType) !== symbolFunction) { if (getSymbol(funType) !== symbolFunction) {
throw new NotAFunctionError(`${prettyT(funType)} is not a function type!`); throw new NotAFunctionError(`${prettyT(funType)} is not a function type!`);
} }
[funType, paramType] = recomputeTypeVars([funType, paramType]); const [[refunType, funS], [reparamType, paramS]] = recomputeTypeVarsSubstitutions([funType, paramType]);
// console.log(prettyT(funType), prettyT(paramType)); const [inType, outType] = refunType.params.map(p => p(refunType));
const [inType, outType] = funType.params.map(p => p(funType)); const {substitutions} = __unify(inType, reparamType);
const {substitutions} = __unify(inType, paramType);
// console.log(substitutions, prettyT(outType)); // console.log(substitutions, prettyT(outType));
const substitutedFnType = substitute(outType, substitutions); const substitutedFnType = substitute(outType, substitutions);
const computedOutType = recomputeTypeVars([substitutedFnType])[0]; const computedOutType = recomputeTypeVars([substitutedFnType])[0];
return [computedOutType, substitutions]; return [computedOutType, substitutions];
} };
// Ensures that no type variables overlap // Ensures that no type variables overlap
export const recomputeTypeVars = types => { export const recomputeTypeVars = types => {
return recomputeTypeVarsSubstitutions(types)
.map(([newType, _subst]) => newType);
};
export const recomputeTypeVarsSubstitutions = types => {
let nextIdx = 0; let nextIdx = 0;
return types.map(type => { return types.map(type => {
const substitutions = new Map(); const substitutions = new Map();
@ -215,6 +219,6 @@ export const recomputeTypeVars = types => {
for (const typeVar of typeVars) { for (const typeVar of typeVars) {
substitutions.set(typeVar, TYPE_VARS[nextIdx++]); substitutions.set(typeVar, TYPE_VARS[nextIdx++]);
} }
return substitute(type, substitutions); return [substitute(type, substitutions), substitutions];
}); });
} };