This module defines type checking functions for generalizing inferred types and applying context reduction (generalise').
module TiGeneralize where import TiMonad import TiTypes import TiUtil import TiSolve(solve,TypeConstraint(..)) import Unification(isVar) import TiNames(ValueId,TypeVar,dictName,dictName') import TiClasses hiding (isVar) import TiKinds --import TiPrelude import TiContextReduction import TiDefault import TiFunDeps(predDeps,closure,improvement) import TiFresh import HasBaseStruct import HsConstants(mod_Prelude,tuple) import BaseSyntax(srcLoc,TI(..)) import TypedIds(NameSpace(..)) import PrettyPrint hiding (var) import List((\\),partition,nub)--,intersect import MUtils --import Debug.Trace(trace) -- debug
If there were polymorphic kinds, kgeneralise would produce kind schemes, but currently it just instantiates any remaining kind variables after kind inference to *, in accordance with the Haskell 98 report, section 4.6.
kgeneralise m = do (kbs,s) <- getKSubst m return $ (map.fmap) (fixkvars . ksubst s) kbs
As kgeneralise, but treat Pred as equal to *. Useful for kind checking after the dictionary translation.
kgeneraliseSloppy m = do (kbs,s) <- getKSubstSloppy m return $ (map.fmap) (apFst (fixkvars . ksubst s)) kbs --generalise1 u = generalise' u id --generalise u = generalise' u fmap
At the moment, checkKinds only keeps track of the kinds of type variables that remain after type inference. It could be improved to also check that all subsitutions performed were kind preserving.
checkKinds kpreds = return (tyvars kpreds) where --tyvars :: Unifiable i => [Kinded (Type i)] -> [Kinded i] tyvars kpreds = nub [v:>:k|t:>:k<-kpreds,Just v<-[isVar t]] -- hmm {- catchAmbiguity dicts = if null dicts then done else fail $ pp ("Unresolved overloading: "<+>ppDicts dicts) -}
Iterate context reduction and improvement until nothing changes
reduceAndImprove dicts0 = do (dicts1,r1) <- contextReduction dicts0 subst1@(S s) <- errorContext "Applying functional dependencies" $ improvement [ p | d:>:p<-dicts1] if null s then return (dicts1,r1,subst1) else do --trace (pp $ "Improvement:"<+>vcat [ppi s,"of"<+>ppi dicts1]) $ done (dicts2,r2,subst2) <- reduceAndImprove (apply subst1 dicts1) return (dicts2,r2 . r1,compS subst2 subst1)
Generalize inferred types:
generalise' keepambig unrestricted fmap' m = do env <- getTEnv (x:>:t0,res@(dicts0,kpreds0,subst0)) <- getSubst m --trace (pp (t0,res)) $ return () ((dicts,r,subst1),([],kpreds1,S [])) <- getSubst $ reduceAndImprove dicts0 let subst@(S s) = compS subst1 subst0 kpreds <- checkKinds (kpreds1++[apply subst1 t:>:k|t:>:k<-kpreds0]) --trace (pp kpreds) $ return () mono <- monomorphism # getEnv -- The monomorphism restriction is optional! fdeps <- predDeps [ p | d:>:p<-dicts] let t = apply subst t0 ngvs0 = tv env -- could probably be made more efficient... s' = [s1|s1@(v,_)<-s,v `elem` ngvs0] -- Non-generic variables by the usual Hindley-Milner rules: hmngvs0 = ngvs0++tv (map snd s') -- Non-generic vars when taking functional dependencies into account: hmngvs = closure fdeps hmngvs0 -- (deferred,retained) predicates: (ngdicts,gdicts0) = if not mono || unrestricted then partition ng dicts else (dicts,[]) -- monomorphism restriction applies where ng = all (`elem` hmngvs) . tv mrngvs = tv ngdicts ngvs = hmngvs++ -- the usual Hindley-Milner restriction mrngvs -- from the monomorphism restriction (ngkpreds,gkpreds0) = partition ng kpreds where ng (v:>:k) = v `elem` ngvs -- mrngvs is not enough! --(avs,(ambigdicts,gdicts)) = ambiguities ngvs gdicts0 t --catchAmbiguity ambigdicts; let subst' = idS; r' = id (gdicts,(subst',r')) <- let known = (if keepambig then tdom gkpreds0 else [])++{-hm-}ngvs in resolveAmbiguities fdeps known gdicts0 t gkpreds <- checkKinds [varSubst subst' v:>:k|v:>:k<-gkpreds0] let ds:>:ctx = unzipTyped gdicts gvs = tdom gkpreds ks = map (emap HsVar) gkpreds gen t = Forall ags (kinded ks gs) qt where ags = filter (\ (v:>:_)->v `notElem` gs) gkpreds qt = ctx:=>t gs = tv qt \\ ngvs -- normal type scheme --gs = gvs \\ ngvs -- keep "ambiguous" type variables sc = fmap' gen t mapM_ constrain [tyvar v:=:t|(v,t)<-s'] -- deferred equality constraints mapM_ addinst ngdicts -- deferred predicates --trace (pp $ "ngkpreds:"<+>ngkpreds) $ return () mapM_ addkinst [tyvar v:>:k|v:>:k<-ngkpreds] -- what to propagate? --abstract ds (r (apply subst x))>:fmap' gen t (ds,r' $ apply subst' $ r $ apply subst x)>:sc getSubst m = do env <- getKEnv ; getSubst' (solve env) m getKSubst = getSubst' ksolve getKSubstSloppy = getSubst' ksolveSloppy getSubst' solve m = do (ans,cs) <- getConstraints m subst <- solve cs return (ans,subst)