module ADP.Fusion.Core.TH.Backtrack where
import Control.Applicative ( (<$>) )
import Control.Monad
import Control.Monad.Primitive (PrimState, PrimMonad)
import Data.List
import Data.Tuple.Select
import Data.Vector.Fusion.Stream.Monadic (Stream(..))
import Debug.Trace
import Language.Haskell.TH
import Language.Haskell.TH.Instances
import Language.Haskell.TH.Syntax
import qualified Data.Map.Strict as M
import qualified Data.Vector as V
import qualified Data.Vector.Fusion.Stream.Monadic as SM
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Generic.Mutable as VGM
import qualified Data.Vector.Mutable as VM
import qualified Data.Set as S
import Data.PrimitiveArray ( (:.)(..) , Z(..) )
import ADP.Fusion.Core.TH.Common
import Control.Monad.Reader
class ProductBacktracking sigF sigB where
type SigBacktracking sigF sigB :: *
(<||) :: sigF -> sigB -> SigBacktracking sigF sigB
class ProductCombining sigF sigB where
type SigCombining sigF sigB :: *
(**>) :: sigF -> sigB -> SigCombining sigF sigB
makeProductInstances :: Name -> Q [Dec]
makeProductInstances tyconName = do
t <- reify tyconName
case t of
#if MIN_VERSION_template_haskell(2,11,0)
TyConI (DataD ctx tyConName args maybeKind cs d) -> do
#else
TyConI (DataD ctx tyConName args cs d) -> do
#endif
let m = getMonadName args
case cs of
[RecC dataconName funs] -> do
let Just (h,m',x,r) = getObjectiveNames funs
mL <- newName "mL"
xL <- newName "xL"
rL <- newName "rL"
mR <- newName "mR"
xR <- newName "xR"
rR <- newName "rR"
let lType = buildRightType tyconName (m', x, r) (mL, xL, rL) args
let rType = buildRightType tyconName (m', x, r) (mR, xR, rR) args
let (fs,hs) = partition ((`notElem` [h]) . sel1) funs
sigBType <- buildSigBacktrackingType tyconName (m', x, r) xL (mR, xR, rR) args
Clause psB (NormalB bB) dsB <- genAlgProdFunctions buildBacktrackingChoice dataconName funs fs hs
iB <- [d| instance (Monad $(varT mL), Monad $(varT mR), Eq $(varT xL), $(varT mL) ~ $(varT mR), $(varT xL) ~ $(varT rL))
=> ProductBacktracking $(return lType) $(return rType) where
type SigBacktracking $(return lType) $(return rType) = $(return sigBType)
(<||) = $(return $ LamE psB $ LetE dsB bB)
|]
vG <- newName "vG"
sigPType <- buildSigCombiningType tyconName vG (m', x, r) (mL, xL, rL) (mR, xR, rR) args
Clause psC (NormalB bC) dsC <- genAlgProdFunctions buildCombiningChoice dataconName funs fs hs
iC <- [d| instance (Monad $(varT mL), Monad $(varT mR), Eq $(varT xL), Ord $(varT xL), Ord $(varT xR), $(varT mL) ~ $(varT mR) )
=> ProductCombining $(return lType) $(return rType) where
type SigCombining $(return lType) $(return rType) = $(return sigPType)
(**>) = $(return $ LamE psC $ LetE dsC bC)
|]
return $ iB ++ iC
getMonadName :: [TyVarBndr] -> Maybe Name
getMonadName = go
where go [] = Nothing
go (KindedTV m (AppT (AppT ArrowT StarT) StarT) : _) = Just m
go (_ : xs) = go xs
getObjectiveNames :: [VarStrictType] -> Maybe (Name,Name,Name,Name)
getObjectiveNames = go
where go [] = Nothing
go ( (hName , _ , (AppT (AppT ArrowT (AppT (AppT (ConT streamName) (VarT mS)) (VarT x))) (AppT (VarT mR) (VarT r)))) : xs)
| streamName == ''Stream && mS == mR = Just (hName,mS,x,r)
| otherwise = go xs
go ( _ : xs) = go xs
buildLeftType :: Name -> (Name, Name, Name) -> (Name, Name) -> [TyVarBndr] -> Type
buildLeftType tycon (m, x, r) (mL, xL) = foldl AppT (ConT tycon) . map (VarT . go)
where go (PlainTV z)
| z == m = mL
| z == x = xL
| z == r = xL
| otherwise = z
go (KindedTV z _) = go (PlainTV z)
buildRightType :: Name -> (Name, Name, Name) -> (Name, Name, Name) -> [TyVarBndr] -> Type
buildRightType tycon (m, x, r) (mR, xR, rR) = foldl AppT (ConT tycon) . map (VarT . go)
where go (PlainTV z)
| z == m = mR
| z == x = xR
| z == r = rR
| otherwise = z
go (KindedTV z _) = go (PlainTV z)
buildSigBacktrackingType :: Name -> (Name, Name, Name) -> (Name) -> (Name, Name, Name) -> [TyVarBndr] -> TypeQ
buildSigBacktrackingType tycon (m, x, r) (xL) (mR, xR, rR) = foldl appT (conT tycon) . map go
where go (PlainTV z)
| z == m = varT mR
| z == x = [t| ($(varT xL) , [ $(varT xR) ] ) |]
| z == r = varT rR
| otherwise = varT z
go (KindedTV z _) = go (PlainTV z)
buildSigCombiningType :: Name -> Name -> (Name, Name, Name) -> (Name, Name, Name) -> (Name, Name, Name) -> [TyVarBndr] -> TypeQ
buildSigCombiningType tycon vG (m, x, r) (mL, xL, rL) (mR, xR, rR) = foldl appT (conT tycon) . map go
where go (PlainTV z)
| z == m = varT mR
| z == x = [t| ($(varT xL) , [ $(varT xR) ] ) |]
| z == r = [t| V.Vector ($(varT rL) , $(varT rR)) |]
| otherwise = varT z
go (KindedTV z _) = go (PlainTV z)
genAlgProdFunctions
:: Choice
-> Name
-> [VarStrictType]
-> [VarStrictType]
-> [VarStrictType]
-> Q Clause
genAlgProdFunctions choice conName allFunNames evalFunNames choiceFunNames = do
let nonTermNames = nub . map getRuleResultType $ evalFunNames
nameL <- newName "l"
varL <- varP nameL
fnmsL <- sequence $ replicate (length allFunNames) (newName "fnamL")
nameR <- newName "r"
varR <- varP nameR
fnmsR <- sequence $ replicate (length allFunNames) (newName "fnamR")
whereL <- valD (conP conName (map varP fnmsL)) (normalB $ varE nameL) []
whereR <- valD (conP conName (map varP fnmsR)) (normalB $ varE nameR) []
rce <- recConE conName
$ zipWith3 (genChoiceFunction choice) (drop (length evalFunNames) fnmsL) (drop (length evalFunNames) fnmsR) choiceFunNames
++ zipWith3 (genAttributeFunction nonTermNames) fnmsL fnmsR evalFunNames
let cls = Clause [varL, varR] (NormalB rce) [whereL,whereR]
return cls
genChoiceFunction
:: Choice
-> Name
-> Name
-> VarStrictType
-> Q (Name,Exp)
genChoiceFunction choice hL hR (name,_,t) = do
exp <- choice hL hR
return (name,exp)
genAttributeFunction
:: [Name]
-> Name
-> Name
-> VarStrictType
-> Q (Name,Exp)
genAttributeFunction nts fL fR (name,_,t) = do
(lamPat,funL,funR) <-recBuildLamPat nts fL fR (init $ getRuleSynVarNames nts t)
let exp = LamE lamPat $ TupE [funL,funR]
return (name,exp)
recBuildLamPat
:: [Name]
-> Name
-> Name
-> [ArgTy Name]
-> Q ([Pat], Exp, Exp)
recBuildLamPat nts fL' fR' ts = do
ps <- mapM argTyArgs ts
lamPat <- buildLamPat ps
lfun <- buildLns (VarE fL') ps
rfun <- buildRns (VarE fR') ps
return (lamPat, lfun, rfun)
buildLamPat :: [ArgTy Pat] -> Q [Pat]
buildLamPat = mapM go where
go (SynVar p ) = return p
go (Term p ) = return p
go (StackedVars ps) = build ps
build :: [ArgTy Pat] -> Q Pat
build = foldl (\s v -> [p| $(s) :. $(return v) |]) [p|Z|] . map get
get :: ArgTy Pat -> Pat
get (SynVar p) = p
get (Term p) = p
argTyArgs :: ArgTy Name -> Q (ArgTy Pat)
argTyArgs (SynVar n) = SynVar <$> tupP [newName "x" >>= varP , newName "ys" >>= varP]
argTyArgs (Term n) = Term <$> (newName "t" >>= varP)
argTyArgs (StackedTerms _) = Term <$> (newName "t" >>= varP)
argTyArgs (StackedVars vs) = StackedVars <$> mapM argTyArgs vs
argTyArgs NilVar = Term <$> (newName "t" >>= varP)
argTyArgs (Result _) = error "argTyArgs: should not receive @Result@"
buildLns
:: Exp
-> [ArgTy Pat]
-> ExpQ
buildLns f' ps = foldl go (return f') ps
where go :: ExpQ -> ArgTy Pat -> ExpQ
go f (SynVar (TupP [VarP v,_])) = appE f (varE v)
go f (Term (VarP v )) = appE f (varE v)
go f (StackedVars vs ) = appE f (build vs)
build :: [ArgTy Pat] -> ExpQ
build = foldl (\s v -> [| $(s) :. $(varE v) |]) [|Z|] . map get
get (SynVar (TupP [VarP v,_])) = v
get (Term (VarP t) ) = t
buildRns
:: Exp
-> [ArgTy Pat]
-> ExpQ
buildRns f' ps = do
sy :: M.Map Pat Name <- M.fromList <$> (mapM (\s -> newName "y" >>= \y -> return (s,y)) $ concatMap flattenSynVars ps)
let rs = map (\k@(TupP [_,VarP v]) -> BindS (VarP $ sy M.! k) (VarE v)) $ concatMap flattenSynVars ps
let go :: ExpQ -> ArgTy Pat -> ExpQ
go f (SynVar k ) = appE f (varE $ sy M.! k)
go f (Term (VarP v)) = appE f (varE v)
go f (StackedVars vs ) = appE f (foldl build [|Z|] vs)
build :: ExpQ -> ArgTy Pat -> ExpQ
build s (SynVar k ) = [| $(s) :. $(varE $ sy M.! k) |]
build s (Term (VarP v)) = [| $(s) :. $(varE v) |]
funApp <- foldl go (return f') ps
return . CompE $ rs ++ [NoBindS funApp]
type Choice = Name -> Name -> Q Exp
buildBacktrackingChoice :: Choice
buildBacktrackingChoice hL' hR' =
[| \xs -> do
ysM <- SM.toList xs
hFres <- $(varE hL') $ SM.map fst $ SM.fromList ysM
$(varE hR') $ SM.fromList $ concatMap snd $ filter ((hFres==) . fst) $ ysM
|]
buildCombiningChoice :: Choice
buildCombiningChoice hL' hR' =
[| \xs -> do
return undefined
|]
streamToVectorM :: (Monad m, VG.Vector v a) => SM.Stream m a -> m (v a)
streamToVectorM s = SM.toList s >>= return . VG.fromList
getRuleSynVarNames :: [Name]-> Type -> [ArgTy Name]
getRuleSynVarNames nts t' = go t' where
go t
| VarT x <- t = [Result x]
| AppT (AppT ArrowT (VarT x) ) y <- t = (if x `elem` nts then SynVar x else Term x) : go y
| AppT (AppT ArrowT (TupleT 0)) y <- t = NilVar : go y
| AppT (AppT ArrowT s ) y <- t = stacked s : go y
| otherwise = error $ "getRuleSynVarNames error: " ++ show t ++ " in: " ++ show t'
stacked s = if null [ () | SynVar _ <- xs ] then StackedTerms xs else StackedVars xs
where xs = reverse $ stckd s
stckd (ConT z) | z == ''Z = []
stckd (AppT a (TupleT 0)) = NilVar : stckd a
stckd (AppT a (VarT x) ) = (if x `elem` nts then SynVar x else Term x) : stckd a
stckd (AppT (ConT c) a ) | c == ''(:.) = stckd a
stckd err = error $ "stckd" ++ show err
data ArgTy x
= SynVar { synVarName :: x }
| Term { termName :: x }
| StackedTerms { stackedTerms :: [ArgTy x] }
| StackedVars { stackedVars :: [ArgTy x] }
| NilVar
| Result { result :: x }
deriving (Show,Eq)
unpackArgTy :: Show x => ArgTy x -> x
unpackArgTy = go
where go (SynVar x) = x
go (Term x) = x
go (Result x) = x
go err = error $ "unpackArgTy " ++ show err
flattenSynVars :: ArgTy x -> [x]
flattenSynVars (SynVar x) = [x]
flattenSynVars (StackedVars xs) = concatMap flattenSynVars xs
flattenSynVars _ = []