I'm trying to get a deep understanding of a (great) paper "Typing Haskell in Haskell". I'm having difficulties understanding the implementation of two methods there — the mgu
and match
.
Let's talk about the TAp
case (full implementation in the article):
-- Substitutions are from a type variable to a type
type Subst = [(Tyvar, Type)]
-- Calculate most general unifier 's' so that:
-- prop> apply s t1 = apply s t2
mgu :: Monad m => Ty.Type -> Ty.Type -> m Subst
mgu (TAp l r) (TAp l' r') = do s1 <- mgu l l'
s2 <- mgu (apply s1 r) (apply s1 r')
return (s2 @@ s1) -- <=== THIS
-- ...snip...
-- Matching of t1 and t2 finds a substitution 's' so that:
-- prop> apply s t1 = t2
match :: Monad m => Type -> Type -> m Subst
match (TAp l r) (TAp l' r') = do sl <- match l l'
sr <- match r r'
merge sl sr -- <=== THIS
-- ...snip...
-- Substitution composition such that:
-- prop> apply (s1 @@ s2) = apply s1 . apply s2
(@@) :: Subst -> Subst -> Subst
s1 @@ s2 = [ (u, apply s1 t) | (u,t) <- s2 ] ++ s1
-- A `symmetric' composition of substitutions such that:
-- prop> apply (s1++s2) = apply (s2++s1)
merge :: Monad m => Subst -> Subst -> m Subst
merge s1 s2 = if agree then return (s1 ++ s2) else fail "merge fails"
where agree = all (\v -> apply s1 (Ty.TVar v) == apply s2 (Ty.TVar v))
(map fst s1 `intersect` map fst s2)
match
is used only for matching predicates, mgu
is used more often e.g. for actual type inference.
I can't wrap my head on why in the mgu
the substitution composition is sequential and in match
a symmetric composition is used. Why's that?
Furthermore, would it make a difference if I'd change the ordering of unification, so mgu
would read:
mgu (TAp l r) (TAp l' r') = do s1 <- mgu r r'
s2 <- mgu (apply s1 l) (apply s1 l')
return (s2 @@ s1)