module Feldspar.Core.Constructs.Binding
( module Language.Syntactic.Constructs.Binding
, optimizeLambda
, optimizeFunction
, subst
, betaReduce
, prjLambda
, cLambda
, reuseCLambda
, collectLetBinders
) where
import Control.Monad.Reader
import Data.Maybe
import Data.Map
import Data.Typeable (Typeable, gcast)
import Language.Syntactic
import Language.Syntactic.Constructs.Binding hiding (subst,betaReduce)
import Language.Syntactic.Constructs.Binding.HigherOrder (CLambda)
import Feldspar.Lattice
import Feldspar.Core.Types
import Feldspar.Core.Interpretation
instance Sharable Variable
instance Sharable Lambda
instance Sharable Let
instance Monotonic Variable
instance Monotonic Lambda
instance Monotonic Let
subst :: forall dom a b
. ( Constrained dom
, CLambda Type :<: dom
, (Variable :|| Type) :<: dom
)
=> VarId
-> ASTF (dom :|| Typeable) a
-> ASTF (dom :|| Typeable) b
-> ASTF (dom :|| Typeable) b
subst v new = go
where
go :: AST (dom :|| Typeable) c -> AST (dom :|| Typeable) c
go a@((prjLambda -> Just (SubConstr2 (Lambda w))) :$ _)
| v==w = a
go (f :$ a) = go f :$ go a
go var
| Just (C' (Variable w)) <- prjF var
, v==w
, Dict <- exprDictSub pTypeable new
, Dict <- exprDictSub pTypeable var
, Just new' <- gcast new
= new'
go a = a
betaReduce
:: ( Constrained dom
, CLambda Type :<: dom
, (Variable :|| Type) :<: dom
)
=> ASTF (dom :|| Typeable) a
-> ASTF (dom :|| Typeable) (a -> b)
-> ASTF (dom :|| Typeable) b
betaReduce new (lam :$ body)
| Just (SubConstr2 (Lambda v)) <- prjLambda lam = subst v new body
optimizeLambda :: ( CLambda Type :<: dom
, OptimizeSuper dom)
=> FeldOpts
-> (ASTF (dom :|| Typeable) b -> Opt (ASTF (Decor Info (dom :|| Typeable)) b))
-> Info a
-> CLambda Type (b :-> Full (a -> b))
-> Args (AST (dom :|| Typeable)) (b :-> Full (a -> b))
-> Opt (ASTF (Decor Info (dom :|| Typeable)) (a -> b))
optimizeLambda opts opt info lam@(SubConstr2 (Lambda v)) (body :* Nil)
| Dict <- exprDict body
= do
body' <- localVar v info $ opt body
constructFeatUnOpt opts lam (body' :* Nil)
optimizeFunction :: ( (Variable :|| Type) :<: dom
, CLambda Type :<: dom
, Let :<: dom
, OptimizeSuper dom
)
=> FeldOpts
-> (ASTF (dom :|| Typeable) b -> Opt (ASTF (Decor Info (dom :|| Typeable)) b))
-> Info a
-> (ASTF (dom :|| Typeable) (a -> b) -> Opt (ASTF (Decor Info (dom :|| Typeable)) (a -> b)))
optimizeFunction opts opt info e
| e'@(bs, _) <- collectLetBinders e
, not (Prelude.null bs)
= optimizeLet opts opt info e'
optimizeFunction opts opt info a@(sym :$ body)
| Dict <- exprDict a
, Dict <- exprDict body
, Just (lam@(SubConstr2 (Lambda _))) <- prjLambda sym
= optimizeLambda opts opt info lam (body :* Nil)
optimizeFunction _ _ info a
= error $ "optimizeFunction: AST is not a function: " ++ show a ++ "\n" ++ show (infoType info)
optimizeLet
:: ( (Variable :|| Type) :<: dom
, CLambda Type :<: dom
, Let :<: dom
, OptimizeSuper dom
)
=> FeldOpts
-> (ASTF (dom :|| Typeable) b -> Opt (ASTF (Decor Info (dom :|| Typeable)) b))
-> Info a
-> ([(VarId, ASTB (dom :|| Typeable) Type)], ASTF (dom :|| Typeable) (a -> b))
-> Opt (ASTF (Decor Info (dom :|| Typeable)) (a -> b))
optimizeLet opts opt info ((v, ASTB e):t, bd)
| Dict <- exprDict bd
, Dict <- exprDict e
= do
e' <- optimizeM opts e
bd' <- localVar v (getInfo e') $ optimizeLet opts opt info (t, bd)
bd'' <- constructFeatUnOpt opts (cLambda v) (bd' :* Nil)
constructFeatUnOpt opts Let (e' :* bd'' :* Nil)
optimizeLet opts opt info ([], e) = optimizeFunction opts opt info e
instance ( (Variable :|| Type) :<: dom
, OptimizeSuper dom)
=> Optimize (Variable :|| Type) dom
where
constructFeatUnOpt _ (C' (Variable v)) Nil
= reader $ \env -> case Prelude.lookup v (varEnv env) of
Nothing -> error $
"optimizeFeat: can't get size of free variable: v" ++ show v
Just (SomeInfo info) ->
let info' = (fromJust $ gcast info) {infoVars = singleton v (SomeType $ infoType info) }
in Sym $ Decor info' $ C' $ inj $ c' (Variable v)
instance ( CLambda Type :<: dom
, OptimizeSuper dom)
=> Optimize (CLambda Type) dom
where
optimizeFeat opts lam@(SubConstr2 (Lambda _))
| Dict <- exprDict lam
= optimizeLambda opts (optimizeM opts) (mkInfo universal) lam
constructFeatUnOpt _ lam@(SubConstr2 (Lambda v)) (body :* Nil)
| Dict <- exprDict lam
, Info t sz vars _ <- getInfo body
= do
src <- asks sourceEnv
let info = Info (FunType typeRep t) (universal, sz) (delete v vars) src
return $ (Sym $ Decor info $ C' $ inj lam) :$ body
instance SizeProp Let
where
sizeProp Let (_ :* WrapFull f :* Nil) = snd $ infoSize f
instance
( Let :<: dom
, (Variable :|| Type) :<: dom
, CLambda Type :<: dom
, OptimizeSuper dom
) =>
Optimize Let dom
where
optimizeFeat opts lt@Let (a :* f :* Nil) = do
a' <- optimizeM opts a
f' <- optimizeFunction opts (optimizeM opts) (getInfo a') f
constructFeat opts lt (a' :* f' :* Nil)
constructFeatOpt _ Let (a :* (lam :$ var) :* Nil)
| Just (C' (Variable v2)) <- prjF var
, Just (SubConstr2 (Lambda v1)) <- prjLambda lam
, v1 == v2
= return $ fromJust $ gcast a
constructFeatOpt opts Let (var :* f :* Nil)
| Just (C' (Variable _)) <- prjF var
= optimizeM opts $ betaReduce (stripDecor var) (stripDecor f)
constructFeatOpt opts lt1@Let ((lt2 :$ x :$ (lam :$ bd)) :* y :* Nil)
| Just Let <- prj lt2
, Just lam'@(SubConstr2 (Lambda _)) <- prjLambda lam
, SICS `inTarget` opts
= do
bb <- constructFeat opts lt1 (bd :* y :* Nil)
bd' <- constructFeat opts (reuseCLambda lam') (bb :* Nil)
constructFeatUnOpt opts Let (x :* bd' :* Nil)
constructFeatOpt opts lt1@Let (e :* (lam1 :$ (lt2 :$ v :$ (lam2 :$ bd))) :* Nil)
| Just Let <- prj lt2
, Nothing <- viewLiteral e
, Just _ <- viewLiteral v
, Just lam1'@(SubConstr2 (Lambda{})) <- prjLambda lam1
, Just lam2'@(SubConstr2 (Lambda{})) <- prjLambda lam2
, SICS `inTarget` opts
= do
bb <- constructFeat opts (reuseCLambda lam1') (bd :* Nil)
bb' <- constructFeat opts lt1 (e :* bb :* Nil)
bd' <- constructFeat opts (reuseCLambda lam2') (bb' :* Nil)
constructFeatUnOpt opts Let (v :* bd' :* Nil)
constructFeatOpt opts a args = constructFeatUnOpt opts a args
constructFeatUnOpt opts Let args@(_ :* (lam :$ body) :* Nil)
| Just (SubConstr2 (Lambda _)) <- prjLambda lam
, Info {infoType = t} <- getInfo body
= constructFeatUnOptDefaultTyp opts t Let args
prjLambda :: (Project (CLambda Type) dom)
=> dom sig -> Maybe (CLambda Type sig)
prjLambda = prj
cLambda :: Type a => VarId -> CLambda Type (b :-> Full (a -> b))
cLambda = SubConstr2 . Lambda
reuseCLambda :: CLambda Type (b :-> Full (a -> b)) -> CLambda Type (c :-> Full (a -> c))
reuseCLambda (SubConstr2 (Lambda v)) = SubConstr2 (Lambda v)
collectLetBinders :: forall dom a .
( Project Let dom
, Project (CLambda Type) dom
, ConstrainedBy dom Typeable
) => ASTF dom a ->
( [(VarId, ASTB dom Type)]
, ASTF dom a
)
collectLetBinders = go []
where
go
:: [(VarId, ASTB dom Type)]
-> ASTF dom a
-> ( [(VarId, ASTB dom Type)]
, ASTF dom a
)
go bs (lt :$ e :$ (lam :$ body))
| Just (SubConstr2 (Lambda v)) <- prjLambda lam
, Just Let <- prj lt
, Dict <- exprDict e
= go ((v, ASTB e):bs) body
go bs e = (reverse bs, e)