HaRe-0.6: tools/base/TI/TiContextReduction.hs
module TiContextReduction(entails,contextReduction,contextReduction'') where
import TiInstanceDB
import TiClasses
import TiMonad
import TiTypes
import TiBySuper
import TiFresh
import TiFunDeps(improvements)
import TiNames(TypeId,ValueId,dictName)
import TiSCC(sccD')
import TiFreeNames(freeVars)
import TiSolve(expandSynonyms)
import TiUtil(freshen',freshvars)
import SrcLoc1
import PrettyPrint hiding (var)
import List(partition,(\\))
import Monad(msum,mplus)
import MUtils
import Debug.Trace(trace) -- debug
import TiPretty() -- debug
--type Ctx = [Typing QId Pred]
--contextReduction, rmByInst :: HasLocalDef e => IDB -> Ctx -> IM i (Ctx,e->e)
type Dict v = Typing v (Type v)
type Ctx v = [Dict v]
type DDefs v = [(Dict v,DExp v)] -- dictionary definitions
type DictsF v = DDefs v->DDefs v
contextReduction ds = contextReduction' True ds
contextReduction' delayIfOverlap ds =
apSnd returnLets # contextReduction1' delayIfOverlap ds
contextReduction1 ds = contextReduction1' True ds
contextReduction1' delayIfOverlap ds =
do idb <- getIEnv
tenv <- getKEnv
--trace (pp $ caller<+>"contextReduction1 tenv=" $$ nest 2 tenv) done
contextReduction2 delayIfOverlap idb tenv ds
contextReduction2
:: (TypeId v,ValueId v,HasSrcLoc v,Fresh v)
=> Bool -> IDB v -> KEnv v -> Ctx v -> TI v (Ctx v, DictsF v)
contextReduction2 delayIfOverlap idb env =
rmDupCtx & rmBySuper & rmDupCtx & rmByInst delayIfOverlap env idb & rmDupCtx
where
(&) red1 red2 ds =
do (ds1,r1) <- red1 ds
(ds2,r2) <- red2 ds1
return (ds2,r2 . r1)
rmDupCtx = return . rmDupCtx'
rmDupCtx' ds =
case ds of
[] -> ([],id)
(d@(dn:>:dt):ds) ->
case partition (sameInstance d) ds of
(same,other) -> (d:ds',r')
where
r' = foldr l r same
l d' = (letvar' d' dne .)
dne = var dn
(ds',r) = rmDupCtx' other
rmBySuper ds =
do let addSuper (dn:>:dt) = tail # bySuper env (var dn:>:dt)
supds <- concatMapM addSuper ds
let rm ds1 r [] = (reverse ds1,r)
rm ds1 r (d:ds2) =
case filter (sameInstance d) supds of
[] -> rm (d:ds1) r ds2
(supde:>:_):_ -> rm ds1 r' ds2
where r' = letvar' d supde . r
return (rm [] id ds)
superClosure eds env = concatMapM (bySuper env) (map (emap var) eds)
entails eds ids env =
do availds <- superClosure eds env
is <- let _:>:ectx = unzipTyped availds
_:>:ictx = unzipTyped ids
in improvements (ectx++ictx) -- need to skolemize vars in ectx?
let availds' = apply is availds
ids' = apply is ids
_:>:actx = unzipTyped availds'
r <- errorContext ("Given context:"<+>ectx $$
"Should entail:"<+>ictx $$
"Improving substitution:"<+>is) $
returnLets . foldr (.) id # entails' availds' env ids'
return (is,r)
{-
`mplus` fail (pp $ fsep [ppi "contexts don't match:",
ppiFTuple ectx,ppi "vs",ppiFTuple ictx])
-}
where
_:>:ectx = unzipTyped eds
_:>:ictx = unzipTyped ids
entails' availds env = mapM entails0
where
entails0 d@(_:>:dt) =
entails1 d `mplus` (fail $ pp $ "Can not justify:"<+>dt)
entails1 d@(_:>:dt) =
case filter (sameInstance d) availds of
[] -> msum . map entails2 =<< reduceInstOneStep d
(supde:>:_):_ -> return (letvar' d supde)
reduceInstOneStep d@(dn:>:inst) =
do idb <- getIEnv
mapM (use1Inst d) (findInst' False idb (expandSynonyms env inst))
entails2 (ids2,r) = foldr (.) r # mapM entails1 ids2
sameInstance (_:>:t1) (_:>:t2) = t1==t2
rmByInst delayIfOverlap env idb ds =
--stpp ds $
case ds of
[] -> return ([],id)
(d@(dn:>:inst):ds) ->
case findInst' delayIfOverlap idb (expandSynonyms env inst) of
[] -> {-(if null (tv inst)
then trace (pp $ fsep [ppi (srcLoc dn)<>":",
ppi "No instance: ",
ppi inst{-,
ppi "in",
ppi idb-}])
else id) $-}
preserve
[i] -> if True -- null (tv inst) -- delay reduction, ...
then useInst i
else trace (pp $ "Delaying"<+>d<+>srcLoc dn) $
preserve -- ... experiment for overlapping instances
is -> trace msg preserve -- experiment
--fail msg -- normal
where msg = pp $ sep [ppi "Ambiguous instances", "("<>map fst is<>")",
"for"<+>inst]
where
preserve = apFst (d:) # rmByInst delayIfOverlap env idb ds
useInst inst =
do (ids,r1) <- use1Inst d inst
(ds2,r2) <- rmByInst delayIfOverlap env idb (ids++ds)
return (ds2,r2 . r1)
use1Inst d ((idn,ips0),((gs,ip),s)) =
do idns <- map dictName # freshlist (length ips0)
let lgs = [g|g@(v:>:_)<-gs,v `elem` d]
where d = tv ips0 \\ tv ip
lvs <- freshvars lgs
(ips,ts0) <- return $ freshen' lvs (tdom lgs) (ips0,map tyvar (tdom gs))
let dt = funT (ips++[ip])
ids = zipWith (:>:) idns ips
--Forall gs _ = sc
sc = mono dt -- fake, ok since it isn't used
ts = apply s ts0
--idne = var idn -- without type annotations
idne = DSpec (HsVar idn) sc ts -- with type annotations
d' = foldl1 DApp (idne:map var idns)
r1 = letvar' d d'
--trace (pp ((s,gs,ips0:=>ip),(lgs,lvs,ips:=>ip))) $ done
return (ids,r1)
letvar' v e = ((v,e):)
-- Sort dictionary definitions in dependency order and return a nested let.
returnLets r = \s -> foldr (uncurry letvar . apSnd dconv) s (order (r []))
where
order = concat . sccD' names
names (d:>:_,e) = ([HsVar d],dfree e)
--------------------------------------------------------------------------------
-- To avoid an ambiguity when you only want the resulting predicates and
-- not the dictionary rewriting function:
contextReduction'' ds = fst # contextReduction1 ds
data DExp i
= DId (HsIdentI i)
| DApp (DExp i) (DExp i)
| DSpec (HsIdentI i) (Scheme i) [Type i]
dconv de =
case de of
DId i -> ident i
DApp e1 e2 -> app (dconv e1) (dconv e2)
DSpec i sc t -> spec i sc t
instance HasId i (DExp i) where ident = DId
instance HasCoreSyntax i (DExp i) where app = DApp -- ; ...
instance HasTypeApp i (DExp i) where spec = DSpec
dfree de =
case de of
DId i -> [i]
DSpec i _ _ -> [i]
DApp e1 e2 -> dfree e1++dfree e2