{- --------------------------------------------------------------------------- Handling of type substitutions. They substitute NTs for Ids. -} module Type.Subst(Substitute(..),idSubst,substEnv,substCtxs,stripSubst,addSubst,applySubst,list2Subst,strace,substNT) where import NT(NT(..),NewType(..)) import Util.Extra(strace) import Type.Data import qualified Data.Map as Map import Id(Id) import Maybe forceList :: [a] -> b -> b forceList [] c = c forceList (x:xs) c = seq x (forceList xs c) type NTSubst = Map.Map Id NT idSubst :: NTSubst idSubst = Map.empty {- | subst does not just apply the mapping represented by the tree once, but it applies the idempotent closure of the mapping! substNT below only applies the mapping once. -} class Substitute a where subst :: NTSubst -> a -> a instance Substitute NT where subst phi nt@(NTany v) = case Map.lookup v phi of Just nt -> subst phi nt Nothing -> nt subst phi nt@(NTvar v _) = case Map.lookup v phi of Just nt -> subst phi nt Nothing -> nt subst phi nt@(NTexist v _) = nt subst phi (NTcons con k ts) = let ts' = map (subst phi) ts in forceList ts' (NTcons con k ts') subst phi (NTapp t1 t2) = let t2' = subst phi t2 in seq t2' (case subst phi t1 of NTcons con k ts -> (NTcons con k (ts ++ [t2'])) t -> NTapp t t2' ) subst phi nt@(NTcontext con v) = nt instance Substitute NewType where subst phi (NewType free [] ctxs ts) = let ts' = map (subst phi) ts in forceList ts' (NewType free [] ctxs ts') instance Substitute TypeDict where subst phi (TypeDict c nt ip) = let nt' = subst phi nt in seq nt' (TypeDict c nt' ip) substEnv :: Substitute b => NTSubst -> [(a,b)] -> [(a,b)] substEnv phi env = map ( \ (e,nt) -> (e,subst phi nt)) env substCtxs :: Substitute a => NTSubst -> [a] -> [a] substCtxs phi ctxs = map (subst phi) ctxs applySubst :: NTSubst -> Id -> Maybe NT applySubst phi tvar = case Map.lookup tvar phi of Just nt@(NTvar tvar _) -> applySubst' phi nt tvar Just nt@(NTany tvar) -> applySubst' phi nt tvar Just nt -> Just nt Nothing -> Nothing where applySubst' phi nt tvar = case Map.lookup tvar phi of Just nt@(NTvar tvar _) -> applySubst' phi nt tvar Just nt@(NTany tvar) -> applySubst' phi nt tvar Just nt -> Just nt Nothing -> Just nt stripSubst :: NTSubst -> Id -> NTSubst stripSubst phi tvar = phi -- nhc98 doesn't strip substitutions addSubst :: NTSubst -> Id -> NT -> NTSubst addSubst phi tvar t = Map.insertWith (\ a b -> error ("Two mappings for " ++ show tvar ++ " : " ++ show a ++ " and " ++ show b)) tvar t phi list2Subst :: [(Id,NT)] -> NTSubst list2Subst xs = foldr ( \ (v,nt) phi -> addSubst phi v nt) idSubst xs {- | substNT only goes one step, used for (1->2),(2->1) substitutions in TypeCtx -} substNT :: [(Id,NT)] -> NT -> NT substNT tv (NTany a) = fromJust (lookup a tv) substNT tv (NTvar a _) = fromJust (lookup a tv) substNT tv t@(NTexist a _) = t substNT tv (NTstrict t) = NTstrict (substNT tv t) substNT tv (NTapp t1 t2) = NTapp (substNT tv t1) (substNT tv t2) substNT tv (NTcons a k tas) = NTcons a k (map (substNT tv) tas)