cleanup unification a bit

This commit is contained in:
Joeri Exelmans 2025-05-23 14:35:07 +02:00
parent 68bd7cdb9f
commit 2333abe70f

View file

@ -29,6 +29,7 @@ export class SubstitutionCycle extends Error {
} }
} }
// pure
export const subsitutionsEqual = (m1,m2) => { export const subsitutionsEqual = (m1,m2) => {
if (m1.size !== m2.size ) return false; if (m1.size !== m2.size ) return false;
for (const [key1,type1] of m1) { for (const [key1,type1] of m1) {
@ -37,6 +38,7 @@ export const subsitutionsEqual = (m1,m2) => {
return true; return true;
}; };
// pure
// Partial ordering between types // Partial ordering between types
// - deep-equal types are equal (e.g., Int == Int) // - deep-equal types are equal (e.g., Int == Int)
// - non-typevars are smaller than typevars (e.g., Int < a) // - non-typevars are smaller than typevars (e.g., Int < a)
@ -68,17 +70,20 @@ const partialCompareTypes = (typeA, typeB) => {
} }
} }
// pure
const checkCycle = (typevar, type) => { const checkCycle = (typevar, type) => {
if (occurring(type).has(typevar)) { if (occurring(type).has(typevar)) {
throw new SubstitutionCycle(typevar, type); throw new SubstitutionCycle(typevar, type);
} }
} }
// impure, modifies 'substitutions'
const addReduce = (substitutions, typevar, type) => { const addReduce = (substitutions, typevar, type) => {
// console.log('add ', prettyS(typevar, type)); // console.log('add ', prettyS(typevar, type));
substitutions.set(typevar, type); substitutions.set(typevar, type);
} }
// impure, modifies 'substitutions'
const attemptReduce = (substitutions, typevar, type) => { const attemptReduce = (substitutions, typevar, type) => {
// assuming 'substitutions' is already reduced as much as possible, // assuming 'substitutions' is already reduced as much as possible,
// substitute all typevars in our type with the existing substitutions // substitute all typevars in our type with the existing substitutions
@ -108,8 +113,24 @@ const attemptReduce = (substitutions, typevar, type) => {
} }
} }
// pure
export const mergeSubstitutionsN = (substs) => {
return substs.reduce((acc, cur) => {
return mergeSubstitutions2(acc, cur);
}, new Map());
}
// pure
const mergeSubstitutions2 = (substA, substB) => {
const result = new Map(substA);
for (const [typevarB, typeB] of substB) {
attemptReduce(result, typevarB, typeB);
}
return result;
}
// pure
export const unify = (typeA, typeB) => { export const unify = (typeA, typeB) => {
const substitutions = new Map();
try { try {
if (isTypeVar(typeA)) { if (isTypeVar(typeA)) {
if (isTypeVar(typeB)) { if (isTypeVar(typeB)) {
@ -139,20 +160,14 @@ export const unify = (typeA, typeB) => {
throw new IncompabibleTypesError(typeA, typeB); throw new IncompabibleTypesError(typeA, typeB);
} }
const unifiedParams = zip(typeA.params, typeB.params) const subs = zip(typeA.params, typeB.params)
.map(([getParamA, getParamB]) => { .map(([getParamA, getParamB]) => {
const paramA = getParamA(typeA); const paramA = getParamA(typeA);
const paramB = getParamB(typeB); const paramB = getParamB(typeB);
// console.log('request...'); // console.log('request...');
return unify(paramA, paramB); return unify(paramA, paramB);
}); });
return mergeSubstitutionsN(subs);
// merge substitutions
unifiedParams.forEach(subst => {
for (const [typevar, type] of subst) {
attemptReduce(substitutions, typevar, type);
}
});
} }
catch (e) { catch (e) {
if (e instanceof SubstitutionCycle) { if (e instanceof SubstitutionCycle) {
@ -164,5 +179,4 @@ export const unify = (typeA, typeB) => {
} }
throw e; throw e;
} }
return substitutions;
}; };