{-# LANGUAGE CPP #-}
module Transformations.Simplify (simplify) where
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>), (<*>))
#endif
import Control.Monad.Extra (concatMapM)
import Control.Monad.State as S (State, runState, gets, modify)
import qualified Data.Map as Map (Map, empty, insert, lookup)
import Curry.Base.Ident
import Curry.Base.SpanInfo
import Curry.Syntax
import Base.Expr
import Base.Messages (internalError)
import Base.SCC
import Base.Types
import Base.Typing
import Base.Utils
import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)
simplify :: ValueEnv -> Module Type -> (Module Type, ValueEnv)
simplify vEnv mdl@(Module _ _ m _ _ _) = (mdl', valueEnv s')
where (mdl', s') = S.runState (simModule mdl) (SimplifyState m vEnv 1)
data SimplifyState = SimplifyState
{ moduleIdent :: ModuleIdent
, valueEnv :: ValueEnv
, nextId :: Int
}
type SIM = S.State SimplifyState
getModuleIdent :: SIM ModuleIdent
getModuleIdent = S.gets moduleIdent
getNextId :: SIM Int
getNextId = do
nid <- S.gets nextId
S.modify $ \s -> s { nextId = succ nid }
return nid
getFunArity :: QualIdent -> SIM Int
getFunArity f = do
vEnv <- getValueEnv
return $ case qualLookupValue f vEnv of
[Value _ _ a _] -> a
[Label _ _ _] -> 1
_ -> internalError $ "Simplify.funType " ++ show f
getValueEnv :: SIM ValueEnv
getValueEnv = S.gets valueEnv
freshIdent :: (Int -> Ident) -> SIM Ident
freshIdent f = f <$> getNextId
simModule :: Module Type -> SIM (Module Type)
simModule (Module spi ps m es is ds) = Module spi ps m es is
<$> mapM (simDecl Map.empty) ds
type InlineEnv = Map.Map Ident (Expression Type)
simDecl :: InlineEnv -> Decl Type -> SIM (Decl Type)
simDecl env (FunctionDecl p ty f eqs) = FunctionDecl p ty f
<$> concatMapM (simEquation env) eqs
simDecl env (PatternDecl p t rhs) = PatternDecl p t <$> simRhs env rhs
simDecl _ d = return d
simEquation :: InlineEnv -> Equation Type -> SIM [Equation Type]
simEquation env (Equation p lhs rhs) = do
rhs' <- simRhs env rhs
inlineFun env p lhs rhs'
simRhs :: InlineEnv -> Rhs Type -> SIM (Rhs Type)
simRhs env (SimpleRhs p e _) = simpleRhs p <$> simExpr env e
simRhs _ (GuardedRhs _ _ _) = error "Simplify.simRhs: guarded rhs"
inlineFun :: InlineEnv -> SpanInfo -> Lhs Type -> Rhs Type
-> SIM [Equation Type]
inlineFun env p lhs rhs = do
m <- getModuleIdent
case rhs of
SimpleRhs _ (Let NoSpanInfo [FunctionDecl _ _ f' eqs'] e) _
|
f' `notElem` qfv m eqs'
&& and [all isVariablePattern ts1 | Equation _ (FunLhs _ _ ts1) _ <- eqs']
-> do
let a = eqnArity $ head eqs'
(n, vs', e') = etaReduce 0 [] (reverse (snd $ flatLhs lhs)) e
if
e' == Variable NoSpanInfo (typeOf e') (qualify f')
&& n == a
then mapM (mergeEqns p vs') eqs'
else return [Equation p lhs rhs]
_ -> return [Equation p lhs rhs]
where
etaReduce n1 vs (VariablePattern _ ty v : ts1)
(Apply NoSpanInfo e1 (Variable NoSpanInfo _ v'))
| qualify v == v' = etaReduce (n1 + 1) ((ty, v) : vs) ts1 e1
etaReduce n1 vs _ e1 = (n1, vs, e1)
mergeEqns p1 vs (Equation _ (FunLhs _ _ ts2) (SimpleRhs p2 e _))
= Equation p1 lhs <$> simRhs env (simpleRhs p2 (Let NoSpanInfo ds e))
where
ds = zipWith (\t v -> PatternDecl NoSpanInfo t (simpleRhs p2 (uncurry mkVar v)))
ts2
vs
mergeEqns _ _ _ = error "Simplify.inlineFun.mergeEqns: no pattern match"
simExpr :: InlineEnv -> Expression Type -> SIM (Expression Type)
simExpr _ l@(Literal _ _ _) = return l
simExpr _ c@(Constructor _ _ _) = return c
simExpr env v@(Variable _ ty x)
| isQualified x = return v
| otherwise =
maybe (return v) (simExpr env . withType ty) (Map.lookup (unqualify x) env)
simExpr env (Apply _ e1 e2) = case e1 of
Let _ ds e' -> simExpr env (Let NoSpanInfo ds (Apply NoSpanInfo e' e2))
Case _ ct e' bs -> simExpr env (Case NoSpanInfo ct e' (map (applyToAlt e2) bs))
_ -> Apply NoSpanInfo <$> simExpr env e1 <*> simExpr env e2
where
applyToAlt e (Alt p t rhs) = Alt p t (applyToRhs e rhs)
applyToRhs e (SimpleRhs p e1' _) = simpleRhs p (Apply NoSpanInfo e1' e)
applyToRhs _ (GuardedRhs _ _ _) = error "Simplify.simExpr.applyRhs: Guarded rhs"
simExpr env (Let _ ds e) = do
m <- getModuleIdent
dss <- mapM sharePatternRhs ds
simplifyLet env (scc bv (qfv m) (foldr hoistDecls [] (concat dss))) e
simExpr env (Case _ ct e bs) =
Case NoSpanInfo ct <$> simExpr env e <*> mapM (simplifyAlt env) bs
simExpr env (Typed _ e qty) =
flip (Typed NoSpanInfo) qty <$> simExpr env e
simExpr _ _ = error "Simplify.simExpr: no pattern match"
simplifyAlt :: InlineEnv -> Alt Type -> SIM (Alt Type)
simplifyAlt env (Alt p t rhs) = Alt p t <$> simRhs env rhs
sharePatternRhs :: Decl Type -> SIM [Decl Type]
sharePatternRhs (PatternDecl p t rhs) = case t of
VariablePattern _ _ _ -> return [PatternDecl p t rhs]
_ -> do
let ty = typeOf t
v <- freshIdent patternId
return [ PatternDecl p t (simpleRhs p (mkVar ty v))
, PatternDecl p (VariablePattern NoSpanInfo ty v) rhs
]
where patternId n = mkIdent ("_#pat" ++ show n)
sharePatternRhs d = return [d]
hoistDecls :: Decl a -> [Decl a] -> [Decl a]
hoistDecls (PatternDecl p t (SimpleRhs p' (Let NoSpanInfo ds' e) _)) ds
= foldr hoistDecls ds (PatternDecl p t (simpleRhs p' e) : ds')
hoistDecls d ds = d : ds
simplifyLet :: InlineEnv -> [[Decl Type]] -> Expression Type
-> SIM (Expression Type)
simplifyLet env [] e = simExpr env e
simplifyLet env (ds:dss) e = do
m <- getModuleIdent
ds' <- mapM (simDecl env) ds
env' <- inlineVars env ds'
e' <- simplifyLet env' dss e
ds'' <- concatMapM (expandPatternBindings (qfv m ds' ++ qfv m e')) ds'
return $ foldr (mkLet' m) e' (scc bv (qfv m) ds'')
inlineVars :: InlineEnv -> [Decl Type] -> SIM InlineEnv
inlineVars env ds = case ds of
[PatternDecl _ (VariablePattern _ _ v) (SimpleRhs _ e _)] -> do
allowed <- canInlineVar v e
return $ if allowed then Map.insert v e env else env
_ -> return env
where
canInlineVar _ (Literal _ _ _) = return True
canInlineVar _ (Constructor _ _ _) = return True
canInlineVar v (Variable _ _ v')
| isQualified v' = (> 0) <$> getFunArity v'
| otherwise = return $ v /= unqualify v'
canInlineVar _ _ = return False
mkLet' :: ModuleIdent -> [Decl Type] -> Expression Type -> Expression Type
mkLet' m [FreeDecl p vs] e
| null vs' = e
| otherwise = Let NoSpanInfo [FreeDecl p vs'] e
where vs' = filter ((`elem` qfv m e) . varIdent) vs
mkLet' m [PatternDecl _ (VariablePattern _ ty v) (SimpleRhs _ e _)] (Variable _ _ v')
| v' == qualify v && v `notElem` qfv m e = withType ty e
mkLet' m ds e
| not (any (`elem` qfv m e) (bv ds)) = e
| otherwise = Let NoSpanInfo ds e
expandPatternBindings :: [Ident] -> Decl Type -> SIM [Decl Type]
expandPatternBindings fvs d@(PatternDecl p t (SimpleRhs _ e _)) = case t of
VariablePattern _ _ _ -> return [d]
_ ->
mapM mkSelectorDecl (filter ((`elem` fvs) . fst3) (patternVars t))
where
pty = typeOf t
mkSelectorDecl (v, _, vty) = do
let fty = TypeArrow pty vty
f <- freshIdent (updIdentName (++ '#' : idName v) . fpSelectorId)
return $ varDecl p vty v $
Let NoSpanInfo [funDecl p fty f [t] (mkVar vty v)]
(Apply NoSpanInfo (mkVar fty f) e)
expandPatternBindings _ d = return [d]