module Substitution (Sub, applySub, lookupSub, emptySub, extendSub,
makeSub, thenSub, domSub, unifySub)
where
import Type (TVarId, TConId, MonoType (TVar, TCon), freeTVarMono)
import FiniteMap (FM, emptyFM, lookupElseFM, makeFM, extendFM,
thenFM, mapFM, domFM, ranFM)
import Maybe (Maybe, thenM, returnM, failM, guardM)
data Sub = MkSub (FM TVarId MonoType)
rep :: Sub -> FM TVarId MonoType
rep (MkSub f) = f
applySub :: Sub -> MonoType -> MonoType
applySub s (TVar x) = lookupSub s x
applySub s (TCon k ts) = TCon k (map (applySub s) ts)
lookupSub :: Sub -> TVarId -> MonoType
lookupSub s x = lookupElseFM (TVar x) (rep s) x
unitSub :: TVarId -> MonoType -> Sub
unitSub x t = MkSub (makeFM [(x,t)])
emptySub :: Sub
emptySub = MkSub emptyFM
makeSub :: [(TVarId, MonoType)] -> Sub
makeSub xts = MkSub (makeFM xts)
extendSub :: Sub -> TVarId -> MonoType -> Sub
extendSub s x t = s `thenSub` unitSub x (applySub s t)
thenSub :: Sub -> Sub -> Sub
r `thenSub` s = MkSub (mapFM (applySub s) (rep r) `thenFM` rep s)
domSub :: Sub -> [TVarId]
domSub s = domFM (rep s)
unifySub = unify
unify :: MonoType -> MonoType -> Sub -> Maybe Sub
unify (TVar x) u s = unifyTVar x u s
unify t (TVar y) s = unifyTVar y t s
unify (TCon j ts) (TCon k us) s = (j == k) `guardM` unifies ts us s
unifies :: [MonoType] -> [MonoType] -> Sub -> Maybe Sub
unifies [] [] s = returnM s
unifies (t:ts) (u:us) s = unify t u s `thenM` (\s' -> unifies ts us s')
unifyTVar :: TVarId -> MonoType -> Sub -> Maybe Sub
unifyTVar x t s | x `elem` domSub s = unify (lookupSub s x) t s
| TVar x == t = returnM s
| x `elem` freeVars t = failM
| otherwise = returnM (extendSub s x t)
freeVars = freeTVarMono
|