exference-1.6.0.0: src/Language/Haskell/Exference/Core/ExpressionSimplify.hs
module Language.Haskell.Exference.Core.ExpressionSimplify
( simplifyExpression
)
where
import Language.Haskell.Exference.Core.Types
import Language.Haskell.Exference.Core.Expression
import Data.Function ( on )
simplifyExpression :: Expression -> Expression
simplifyExpression = simplifyId . simplifyCompose . simplifyEta . simplifyLets
simplifyLets :: Expression -> Expression
simplifyLets e@ExpVar{} = e
simplifyLets e@ExpName{} = e
simplifyLets (ExpLambda i ty e) = ExpLambda i ty $ simplifyLets e
simplifyLets (ExpApply e1 e2) = ExpApply (simplifyLets e1) (simplifyLets e2)
simplifyLets e@ExpHole{} = e
simplifyLets (ExpLetMatch name vids bindExp inExp) =
ExpLetMatch name vids (simplifyLets bindExp) (simplifyLets inExp)
simplifyLets (ExpLet i ty bindExp inExp) = case countUses i inExp of
0 -> simplifyLets inExp
1 -> simplifyLets $ replaceVar i bindExp inExp
_ -> ExpLet i ty (simplifyLets bindExp) (simplifyLets inExp)
simplifyLets (ExpCaseMatch bindExp alts) =
ExpCaseMatch (simplifyLets bindExp) [ (c, vars, simplifyLets expr)
| (c, vars, expr) <- alts
]
simplifyEta :: Expression -> Expression
simplifyEta e@ExpVar{} = e
simplifyEta e@ExpName{} = e
simplifyEta (ExpLambda i ty e) = simplifyEta' $ ExpLambda i ty $ simplifyEta e
simplifyEta (ExpApply e1 e2) = ExpApply (simplifyEta e1) (simplifyEta e2)
simplifyEta e@ExpHole{} = e
simplifyEta (ExpLetMatch name vids bindExp inExp) =
ExpLetMatch name vids (simplifyEta bindExp) (simplifyEta inExp)
simplifyEta (ExpLet i ty bindExp inExp) =
ExpLet i ty (simplifyEta bindExp) (simplifyEta inExp)
simplifyEta (ExpCaseMatch bindExp alts) =
ExpCaseMatch (simplifyEta bindExp) [ (c, vars, simplifyEta expr)
| (c, vars, expr) <- alts
]
simplifyEta' :: Expression -> Expression
simplifyEta' (ExpLambda i _ (ExpApply e1 (ExpVar j _)))
| i==j && 0==countUses i e1 = e1
simplifyEta' e = e
simplifyId :: Expression -> Expression
simplifyId e@ExpVar{} = e
simplifyId e@ExpName{} = e
simplifyId e@(ExpLambda i _ (ExpVar j _))
| i == j = ExpName (QualifiedName [] "id")
| otherwise = e
simplifyId (ExpLambda i ty e) = ExpLambda i ty $ simplifyId e
simplifyId (ExpApply e1 e2) = ExpApply (simplifyId e1) (simplifyId e2)
simplifyId e@ExpHole{} = e
simplifyId (ExpLetMatch name vids bindExp inExp)
= ExpLetMatch name
vids
(simplifyId bindExp)
(simplifyId inExp)
simplifyId (ExpLet i ty bindExp inExp) =
ExpLet i ty (simplifyId bindExp) (simplifyId inExp)
simplifyId (ExpCaseMatch bindExp alts) =
ExpCaseMatch (simplifyId bindExp) [ (c, vars, simplifyId expr)
| (c, vars, expr) <- alts
]
simplifyCompose :: Expression -> Expression
simplifyCompose e@ExpVar{} = e
simplifyCompose e@ExpName{} = e
simplifyCompose (ExpLambda i ty e) = simplifyCompose' i ty [] e
simplifyCompose (ExpApply e1 e2) = ExpApply (simplifyCompose e1) (simplifyCompose e2)
simplifyCompose e@ExpHole{} = e
simplifyCompose (ExpLetMatch name vids bindExp inExp)
= ExpLetMatch name
vids
(simplifyCompose bindExp)
(simplifyCompose inExp)
simplifyCompose (ExpLet i ty bindExp inExp)
= ExpLet i
ty
(simplifyCompose bindExp)
(simplifyCompose inExp)
simplifyCompose (ExpCaseMatch bindExp alts)
= ExpCaseMatch
(simplifyCompose bindExp)
[ (c, vars, simplifyCompose expr)
| (c, vars, expr) <- alts
]
simplifyCompose' :: Int -> HsType -> [Expression] -> Expression -> Expression
simplifyCompose' i ty [] e@ExpVar{} = ExpLambda i ty e
simplifyCompose' i ty l e@(ExpVar j _)
| i == j = foldl1 (\e1 e2 -> ExpApply
(ExpApply
(ExpName (QualifiedName [] "(.)")) e2) e1)
l
| otherwise = ExpLambda i ty $ foldl (flip ExpApply) e l
simplifyCompose' i ty l (ExpApply e1 e2)
| countUses i e1==0 = simplifyCompose' i ty (simplifyCompose e1:l) e2
simplifyCompose' i ty l e = ExpLambda i ty
$ foldl (flip ExpApply) (simplifyCompose e) l
replaceVar :: TVarId -> Expression -> Expression -> Expression
replaceVar vid t orig@(ExpVar j _) | vid==j = t
| otherwise = orig
replaceVar vid t (ExpLambda i ty e) = ExpLambda i ty $ replaceVar vid t e
replaceVar vid t (ExpApply e1 e2) = ExpApply (replaceVar vid t e1)
(replaceVar vid t e2)
replaceVar vid t (ExpLetMatch n vars bindExp inExp) =
ExpLetMatch n vars (replaceVar vid t bindExp) (replaceVar vid t inExp)
replaceVar vid t (ExpLet i ty bindExp inExp) =
ExpLet i ty (replaceVar vid t bindExp) (replaceVar vid t inExp)
replaceVar vid t (ExpCaseMatch bindExp alts) =
ExpCaseMatch (replaceVar vid t bindExp) [ (c, vars, replaceVar vid t expr)
| (c, vars, expr) <- alts
]
replaceVar _ _ t@(ExpName _) = t
replaceVar _ _ t@(ExpHole _) = t
countUses :: TVarId -> Expression -> Int
countUses i (ExpVar j _) | i==j = 1
| otherwise = 0
countUses _ ExpName{} = 0
countUses i (ExpLambda j _ e) | i==j = 0
| otherwise = countUses i e
countUses i (ExpApply e1 e2) = ((+) `on` countUses i) e1 e2
countUses _ ExpHole{} = 0
countUses i (ExpLetMatch _ _ bindExp inExp) = ((+) `on` countUses i) bindExp inExp
countUses i (ExpLet _ _ bindExp inExp) = ((+) `on` countUses i) bindExp inExp
countUses i (ExpCaseMatch bindExp alts) = sum $ countUses i bindExp
: [ countUses i expr
| (_, _, expr) <- alts
]