--
-- (c) Susumu Katayama
--
\begin{code}
module MagicHaskeller.ProgGenSFIORef(ProgGenSFIORef, PGSFIOR) where
import MagicHaskeller.Types
import MagicHaskeller.TyConLib
import Control.Monad
import MagicHaskeller.CoreLang
import Control.Monad.Search.Combinatorial
import MagicHaskeller.PriorSubsts
import Data.List(partition, sortBy, sort, nub, (\\))
import Data.Ix(inRange)
import MagicHaskeller.ClassifyDM
import MagicHaskeller.Instantiate
import MagicHaskeller.ProgramGenerator
import MagicHaskeller.ProgGen(mkCL, ClassLib(..), mguPrograms)
import MagicHaskeller.ProgGenSF(funApSub_, funApSub_spec, lookupNormalized, tokoro10fst)
import MagicHaskeller.Options(Opt(..))
import MagicHaskeller.Expression
import MagicHaskeller.MemoToFiles hiding (freezePS, fps, memoRTIO)
import MagicHaskeller.T10(mergesortWithBy, diffSortedBy)
import qualified Data.Map as M
import MagicHaskeller.DebMT
import MagicHaskeller.FMType
import Data.IORef
import Data.Array
import Data.Ix
import MagicHaskeller.ShortString(readBriefly, showBriefly)
import System.Directory(doesFileExist, createDirectoryIfMissing)
import Debug.Trace
reorganize_ = reorganizer_
reorganizerId' :: (Functor m, Expression e) => ([Type] -> m e) -> [Type] -> m e
reorganizerId' = reorganizeId'
classify = True
traceExpTy _ = id
traceTy _ = id
type ProgGenSFIORef = PGSFIOR CoreExpr
data PGSFIOR e = PGSFIOR (ExpTrie e) (MemoDeb e)
type ExpTrie e = IORef (FMType (Array Int [e]))
type TypeTrie = MapType (Matrix (Type, Subst, TyVar))
filtBFm cmn ty | classify = inconsistentDBTToRcT . fmap fromAnnExpr . filterDM cmn ty . fmap (toAnnExprWind (execute (opt cmn) (vl cmn)) ty) . mapDepthDB uniqSorter
| otherwise = dbtToRcT . mapDepthDB uniqSorter
lmtty mt fty = traceTy fty $
lookupMT mt fty
memocond i = True
instance ProgramGeneratorIO (PGSFIOR CoreExpr) where
mkTrieOptIO cmn classes tcesopt tces = do expTrie <- newIORef EmptyFMT
return $ PGSFIOR expTrie (mkTrieOptSF cmn classes tcesopt tces)
unifyingProgramsIO ty px = catBags $ fmap (\ (es,_,_) -> map (toAnnExpr $ reducer $ extractCommon px) es) $ dbtToRcT $ unifyingPossibilitiesIO ty px
instance Expression e => WithCommon (PGSFIOR e) where
extractCommon (PGSFIOR _ (_,_,_,cmn)) = cmn
unifyingPossibilitiesIO ty pg = unPS (unifyableExprsIO pg [] ty) emptySubst 0
type MemoDeb e = (ClassLib e, TypeTrie, (([[Prim]],[[Prim]]),([[Prim]],[[Prim]])), Common)
mkTrieOptSF :: Common -> [Typed [CoreExpr]] -> [[Typed [CoreExpr]]] -> [[Typed [CoreExpr]]] -> MemoDeb CoreExpr
mkTrieOptSF cmn classes txsopt txs
= let memoDeb = (mkCL cmn classes, typeTrie, (qtlopt,qtl), cmn)
typeTrie = mkMTty (tcl cmn) (\ty -> freezePS ty (specTypes memoDeb ty))
in memoDeb
where qtlopt = splitPrimss txsopt
qtl = splitPrimss txs
inconsistentDBTToRcT :: (Functor m, Monad m, Ord a) => DBoundT m a -> RecompT m a
inconsistentDBTToRcT (DBT f) = RcT $ \d -> do tss <- mapM f [0..d1]
ts <- f d
return $ foldl (diffSortedBy compare) (map fst ts) (map (map fst) tss)
computeExpTip :: PGSFIOR CoreExpr -> Type -> RecompT IO CoreExpr
computeExpTip md@(PGSFIOR _ (_,_,_,cmn)) ty = filtBFm cmn ty $ matchFunctionsIO md ty
mkMTty = mkMT
mkMTexp = mkMT
mondepth = zipDepthRc (\d xs -> trace ("depth="++show d++", and the length is "++show (length xs)) xs)
type BFT = Recomp
unBFM = unMx
freezePS :: Type -> PriorSubsts Recomp Type -> Matrix (Type,Subst,TyVar)
freezePS ty ps
= let mxty = maxVarID ty
in mapDepth tokoro10ap $ toMx $ fmap fst $ Rc $ unDB $ fromRc $ unPS ps emptySubst (mxty+1)
tokoro10ap :: [(Type,s,i)] -> [(Type,s,i)]
tokoro10ap = M.elems . M.fromListWith const . map (\ t@(ty,_,_) -> (ty, t))
specializedTypes :: (Search m) => MemoDeb CoreExpr -> [Type] -> Type -> PriorSubsts m ([Type],Type)
specializedTypes memodeb avail t = do specializedCases memodeb avail t
subst <- getSubst
return (map (apply subst) avail, apply subst t)
specializedCases, specCases, specCases' :: (Search m) => MemoDeb CoreExpr -> [Type] -> Type -> PriorSubsts m ()
specializedCases memodeb = applyDo (specCases memodeb)
specCases memodeb = wind_ (\avail reqret -> reorganize_ (\newavail -> uniExprs_ memodeb newavail reqret) avail)
uniExprs_ :: (Search m) => MemoDeb CoreExpr -> [Type] -> Type -> PriorSubsts m ()
uniExprs_ memodeb avail t
= convertPS fromRc $ psListToPSRecomp lfp
where lfp depth
| memocond depth = lookupUniExprs memodeb avail t depth >> return ()
| otherwise = makeUniExprs memodeb avail t depth >> return ()
lookupUniExprs :: Expression e => MemoDeb e -> [Type] -> Type -> Int -> PriorSubsts [] Type
lookupUniExprs memodeb@(_,mt,_,_) avail t depth
= lookupNormalized (\tn -> unMx (lmtty mt tn) !! depth) avail t
makeUniExprs :: MemoDeb CoreExpr -> [Type] -> Type -> Int -> PriorSubsts [] Type
makeUniExprs memodeb avail t depth
= convertPS tokoro10fst $
do psRecompToPSList (reorganize_ (\av -> specCases' memodeb av t) avail) depth
sub <- getSubst
return $ quantify (apply sub $ popArgs avail t)
specTypes :: (Search m) => MemoDeb CoreExpr -> Type -> PriorSubsts m Type
specTypes memodeb ty
= do let (avail,t) = splitArgs ty
reorganize_ (\av -> specCases' memodeb av t) avail
typ <- applyPS ty
return (normalize typ)
specCases' memodeb@(CL classLib, ttrie, (prims@(primgen,primmono),_),cmn) avail reqret
= mapSum retPrimMono primmono `mplus` msum (map retMono avail) `mplus` mapSum retGen primgen
where fas | constrL $ opt cmn = funApSub_ clbehalf lltbehalf behalf
| otherwise = funApSub_spec clbehalf behalf
where behalf = specializedCases memodeb avail
lltbehalf = flip mguAssumptions_ avail
clbehalf ty = mguPrograms classLib [] ty >> return ()
retPrimMono (_, arity, retty, numtvs, _xs:::ty)
= napply arity delayPS $
do tvid <- reserveTVars numtvs
mguPS reqret (mapTV (tvid+) retty)
fas (mapTV (tvid+) ty)
retMono ty = napply (getArity ty) delayPS $
do mguPS reqret (getRet ty)
fas ty
retGen (_, arity, _r, numtvs, _s:::ty) = napply arity delayPS $
do tvid <- reserveTVars numtvs
mkSubsts (tvndelay $ opt cmn) tvid reqret
fas (mapTV (tvid+) ty)
gentvar <- applyPS (TV tvid)
guard (orderedAndUsedArgs gentvar)
fas gentvar
type Generator m e = PGSFIOR e -> [Type] -> Type -> PriorSubsts m [e]
unifyableExprsIO :: Generator (DBoundT IO) CoreExpr
unifyableExprsIO memodeb = applyDo (wind (fmap (map (mapCE Lambda))) (lookupNormalized (lookupTypeTrieIO memodeb)))
memocondexp _ d = 0<d
memodepth _ = 1
lookupTypeTrieIO :: PGSFIOR CoreExpr -> Type -> DBoundT IO ([CoreExpr], Subst, TyVar)
lookupTypeTrieIO md@(PGSFIOR _ (_, mt, _, _)) t
= DBT $ \db -> fmap concat $ mapM (procTup md db) $ unMx (lmtty mt t) !! db
procTup :: PGSFIOR CoreExpr -> Int -> (Type, Subst, TyVar) -> IO [(([CoreExpr],Subst,TyVar),Int)]
procTup md db (ty, s, i) = mapM (\depth -> unRcT (lookupReorganizedIO md ty) depth >>= \ys -> return ((ys, s, i), dbdepth)) [0..db]
lookupReorganizedIO md typ = let (avs, retty) = splitArgs $ normalize typ
in reorganizerId' (\av -> lmtIO md $ popArgs av retty) avs
lmtIO :: PGSFIOR CoreExpr -> Type -> RecompT IO CoreExpr
lmtIO md@(PGSFIOR fmtref (_,_,_,cmn)) ty = memoRTIO fmtref (computeExpTip md) ty
memoRTIO :: (Expression e) => ExpTrie e -> (Type -> RecompT IO e) -> Type -> RecompT IO e
memoRTIO fmtref compute ty
= RcT $ \depth -> if memocondexp ty depth then ensureAtHand fmtref compute ty depth
else unRcT (compute ty) depth
ensureAtHand fmtref compute ty depth
= do fmt <- readIORef fmtref
case lookupFMT ty fmt of
Nothing -> makeAtHand fmtref compute ty depth
Just ar | inRange (bounds ar) depth -> return $ ar!depth
| otherwise -> makeAtHand fmtref compute ty depth
makeAtHand fmtref compute ty depth = do result <- unRcT (compute ty) depth
if memocondexp ty (depth1) then do ensureAtHand fmtref compute ty (depth1)
atomicModifyIORef fmtref (addToLast ty depth result)
else atomicModifyIORef fmtref (mkSingle ty depth result)
addToLast :: Expression e => Type -> Int -> [e] -> FMType (Array Int [e]) -> (FMType (Array Int [e]), [e])
addToLast ty depth result fmt = (updateFMT upd (error "addToLast: cannot happen") ty fmt, result)
where upd ar = array (lo,depth) ((depth,result) : assocs ar)
where (lo,_hi) = bounds ar
mkSingle :: Expression e => Type -> Int -> [e] -> FMType (Array Int [e]) -> (FMType (Array Int [e]), [e])
mkSingle ty depth result fmt = (updateFMT (error "mkSingle: I think this cannot happen") (array (depth,depth) [(depth,result)]) ty fmt, result)
matchFunctionsIO :: PGSFIOR CoreExpr -> Type -> DBoundT IO CoreExpr
matchFunctionsIO memodeb ty = case splitArgs (saferQuantify ty) of (avail,t) -> matchFunsIO memodeb avail t
matchFunsIO :: PGSFIOR CoreExpr -> [Type] -> Type -> DBoundT IO CoreExpr
matchFunsIO memodeb avail reqret = catBags $ runPS (matchFuns' unifyableExprsIO memodeb avail reqret)
matchFuns' :: (Search m) => Generator m CoreExpr -> Generator m CoreExpr
matchFuns' rec md@(PGSFIOR _ (CL classLib, _, (_,(primgen,primmono)),cmn)) avail reqret
= let clbehalf = mguPrograms classLib []
behalf = rec md avail
lltbehalf = lookupListrie lenavails rec md avail
lenavails = length avail
fe = filtExprs (guess $ opt cmn)
in fromAssumptions cmn lenavails behalf (\a b -> guard $ a==b) reqret avail `mplus`
mapSum (retPrimMono cmn lenavails clbehalf lltbehalf behalf matchPS reqret) primmono `mplus`
mapSum (( if tv0 $ opt cmn then retGenTV0 else
if tv1 $ opt cmn then retGenTV1 else retGenOrd) cmn lenavails fe clbehalf lltbehalf behalf reqret) primgen
lookupListrie :: (Search m, Expression e) => Int -> Generator m e -> Generator m e
lookupListrie lenavails rec memodeb@(PGSFIOR _ (_,_,_,cmn)) avail t
| constrL opts = matchAssumptions cmn lenavails t avail
| guess opts = do
args <- rec memodeb avail t
let args' = filter (not.isClosed.toCE) args
when (null args') mzero
return args'
| otherwise = do
args <- rec memodeb avail t
let args' = filter (not.isConstrExpr.toCE) args
when (null args') mzero
return args'
where opts = opt cmn
\end{code}