module HERMIT.Dictionary.Local
(
HERMIT.Dictionary.Local.externals
, module HERMIT.Dictionary.Local.Bind
, module HERMIT.Dictionary.Local.Case
, module HERMIT.Dictionary.Local.Cast
, module HERMIT.Dictionary.Local.Let
, abstractR
, pushR
, betaReduceR
, betaExpandR
, etaReduceR
, etaExpandR
, multiEtaExpandR
, flattenModuleR
, flattenProgramR
, flattenProgramT
) where
import HERMIT.Core
import HERMIT.Context
import HERMIT.External
import HERMIT.GHC
import HERMIT.Kure
import HERMIT.Monad
import HERMIT.Name
import HERMIT.Utilities
import HERMIT.Dictionary.Common
import HERMIT.Dictionary.Local.Bind hiding (externals)
import qualified HERMIT.Dictionary.Local.Bind as Bind
import HERMIT.Dictionary.Local.Case hiding (externals)
import qualified HERMIT.Dictionary.Local.Case as Case
import HERMIT.Dictionary.Local.Cast hiding (externals)
import qualified HERMIT.Dictionary.Local.Cast as Cast
import HERMIT.Dictionary.Local.Let hiding (externals)
import qualified HERMIT.Dictionary.Local.Let as Let
import Control.Arrow
externals :: [External]
externals =
[ external "beta-reduce" (promoteExprR betaReduceR :: RewriteH LCore)
[ "((\\ v -> E1) E2) ==> let v = E2 in E1"
, "This form of beta-reduction is safe if E2 is an arbitrary expression"
, "(won't duplicate work)." ] .+ Eval .+ Shallow
, external "beta-expand" (promoteExprR betaExpandR :: RewriteH LCore)
[ "(let v = e1 in e2) ==> (\\ v -> e2) e1" ] .+ Shallow
, external "eta-reduce" (promoteExprR etaReduceR :: RewriteH LCore)
[ "(\\ v -> e1 v) ==> e1" ] .+ Eval .+ Shallow
, external "eta-expand" (promoteExprR . etaExpandR :: String -> RewriteH LCore)
[ "\"eta-expand 'v\" performs e1 ==> (\\ v -> e1 v)" ] .+ Shallow .+ Introduce
, external "flatten-module" (promoteModGutsR flattenModuleR :: RewriteH LCore)
[ "Flatten all the top-level binding groups in the module to a single recursive binding group."
, "This can be useful if you intend to appply GHC RULES." ]
, external "flatten-program" (promoteProgR flattenProgramR :: RewriteH LCore)
[ "Flatten all the top-level binding groups in a program (list of binding groups) to a single"
, "recursive binding group. This can be useful if you intend to apply GHC RULES." ]
, external "abstract" (promoteExprR . abstractR . mkOccPred :: OccurrenceName -> RewriteH LCore)
[ "Abstract over a variable using a lambda."
, "e ==> (\\ x -> e) x" ] .+ Shallow .+ Introduce .+ Context
, external "push" ((\ nm strictf -> push (Just strictf) (cmpString2Var nm)) :: String -> RewriteH LCore -> RewriteH LCore)
[ "Push a function 'f into a case-expression or let-expression argument,"
, "given a proof that f (fully saturated with type arguments) is strict." ] .+ Shallow .+ Commute
, external "push-unsafe" (push Nothing . cmpString2Var :: String -> RewriteH LCore)
[ "Push a function 'f into a case-expression or let-expression argument."
, "Requires 'f to be strict." ] .+ Shallow .+ Commute .+ PreCondition .+ Unsafe
]
++ Bind.externals
++ Case.externals
++ Cast.externals
++ Let.externals
betaReduceR :: MonadCatch m => Rewrite c m CoreExpr
betaReduceR = setFailMsg ("Beta-reduction failed: " ++ wrongExprForm "App (Lam v e1) e2") $
do App (Lam v e1) e2 <- idR
return $ Let (NonRec v e2) e1
betaExpandR :: MonadCatch m => Rewrite c m CoreExpr
betaExpandR = setFailMsg ("Beta-expansion failed: " ++ wrongExprForm "Let (NonRec v e1) e2") $
do Let (NonRec v e1) e2 <- idR
return $ App (Lam v e2) e1
etaReduceR :: MonadCatch m => Rewrite c m CoreExpr
etaReduceR = prefixFailMsg "Eta-reduction failed: " $
withPatFailMsg (wrongExprForm "Lam v (App f (Var v))") $
do Lam v1 (App f e) <- idR
case e of
Var v2 -> guardMsg (v1 == v2) "the expression has the right form, but the variables are not equal."
Type ty -> case getTyVar_maybe ty of
Nothing -> fail "the argument expression is not a type variable."
Just v2 -> guardMsg (v1 == v2) "type variables are not equal."
_ -> fail "the argument expression is not a variable."
guardMsg (v1 `notElemVarSet` freeVarsExpr f) $ unqualifiedName v1 ++ " is free in the function being applied."
return f
etaExpandR :: String -> Rewrite c HermitM CoreExpr
etaExpandR nm = prefixFailMsg "Eta-expansion failed: " $
contextfreeT $ \ e -> let ty = exprKindOrType e in
case splitFunTy_maybe ty of
Just (argTy, _) -> do v <- newIdH nm argTy
return $ Lam v (App e (varToCoreExpr v))
Nothing -> case splitForAllTy_maybe ty of
Just (tv,_) -> do v <- newTyVarH nm (tyVarKind tv)
return $ Lam v (App e (varToCoreExpr v))
Nothing -> fail "type of expression is not a function or a forall."
multiEtaExpandR :: (ExtendPath c Crumb, ReadPath c Crumb, AddBindings c) => [String] -> Rewrite c HermitM CoreExpr
multiEtaExpandR [] = idR
multiEtaExpandR (nm:nms) = etaExpandR nm >>> lamAllR idR (multiEtaExpandR nms)
flattenModuleR :: (ExtendPath c Crumb, HasEmptyContext c, Monad m) => Rewrite c m ModGuts
flattenModuleR = modGutsR flattenProgramR
flattenProgramR :: Monad m => Rewrite c m CoreProg
flattenProgramR = do bnd <- flattenProgramT
return (bindsToProg [bnd])
flattenProgramT :: Monad m => Transform c m CoreProg CoreBind
flattenProgramT = do bds <- arr (concatMap bindToVarExprs . progToBinds)
guardMsg (nodups $ map fst bds) "Top-level bindings contain multiple occurrences of a name."
return (Rec bds)
abstractR :: (ReadBindings c, MonadCatch m, MonadUnique m) => (Var -> Bool) -> Rewrite c m CoreExpr
abstractR p = prefixFailMsg "abstraction failed: " $
do v <- findBoundVarT p
v' <- constT (cloneVarH id v)
e <- arr (substCoreExpr v (varToCoreExpr v'))
return $ mkCoreApp (Lam v' e) (varToCoreExpr v)
push :: Maybe (RewriteH LCore)
-> (Id -> Bool)
-> RewriteH LCore
push mstrict p = promoteExprR (pushR (extractR `fmap` mstrict) p)
pushR :: (ExtendPath c Crumb, ReadPath c Crumb, AddBindings c, ReadBindings c)
=> Maybe (Rewrite c HermitM CoreExpr)
-> (Id -> Bool)
-> Rewrite c HermitM CoreExpr
pushR mstrictf p = prefixFailMsg "push failed: " $
withPatFailMsg (wrongExprForm "App f e") $
do App f e <- idR
case collectArgs f of
(Var i,args) -> do
guardMsg (p i) $ "identifier not matched."
guardMsg (all isTypeArg args) $ "initial arguments are not all type arguments."
case e of
Case {} -> caseFloatArgR (Just f) mstrictf
Let {} -> letFloatArgR
_ -> fail "argument is not a Case or Let."
_ -> fail "no identifier to match."