From 2333abe70f23e1ead428241fbe7c21700072d05b Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 23 May 2025 14:35:07 +0200 Subject: [PATCH] cleanup unification a bit --- lib/generics/unify.js | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/generics/unify.js b/lib/generics/unify.js index 1896371..e727565 100644 --- a/lib/generics/unify.js +++ b/lib/generics/unify.js @@ -29,6 +29,7 @@ export class SubstitutionCycle extends Error { } } +// pure export const subsitutionsEqual = (m1,m2) => { if (m1.size !== m2.size ) return false; for (const [key1,type1] of m1) { @@ -37,6 +38,7 @@ export const subsitutionsEqual = (m1,m2) => { return true; }; +// pure // Partial ordering between types // - deep-equal types are equal (e.g., Int == Int) // - non-typevars are smaller than typevars (e.g., Int < a) @@ -68,17 +70,20 @@ const partialCompareTypes = (typeA, typeB) => { } } +// pure const checkCycle = (typevar, type) => { if (occurring(type).has(typevar)) { throw new SubstitutionCycle(typevar, type); } } +// impure, modifies 'substitutions' const addReduce = (substitutions, typevar, type) => { // console.log('add ', prettyS(typevar, type)); substitutions.set(typevar, type); } +// impure, modifies 'substitutions' const attemptReduce = (substitutions, typevar, type) => { // assuming 'substitutions' is already reduced as much as possible, // 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) => { - const substitutions = new Map(); try { if (isTypeVar(typeA)) { if (isTypeVar(typeB)) { @@ -139,20 +160,14 @@ export const unify = (typeA, typeB) => { throw new IncompabibleTypesError(typeA, typeB); } - const unifiedParams = zip(typeA.params, typeB.params) + const subs = zip(typeA.params, typeB.params) .map(([getParamA, getParamB]) => { const paramA = getParamA(typeA); const paramB = getParamB(typeB); // console.log('request...'); return unify(paramA, paramB); }); - - // merge substitutions - unifiedParams.forEach(subst => { - for (const [typevar, type] of subst) { - attemptReduce(substitutions, typevar, type); - } - }); + return mergeSubstitutionsN(subs); } catch (e) { if (e instanceof SubstitutionCycle) { @@ -164,5 +179,4 @@ export const unify = (typeA, typeB) => { } throw e; } - return substitutions; };