module MonadLab.Reduction (reduceM) where
import Control.Monad
import Language.Haskell.TH
type Env = [(Exp , Exp)]
class Reducible a where
recurse :: (Exp -> Exp) -> a -> a
reduce :: a -> a
reduceM :: Monad m => m a -> m a
subst :: Env -> a -> a
reduce = recurse simpleReduction
reduceM m = m >>= \r -> return (reduce r)
subst env = recurse $ expSubst env
instance Reducible Exp where
recurse f (VarE n) = f $ VarE n
recurse f (ConE n) = f $ ConE n
recurse f (LitE l) = f $ LitE l
recurse f (AppE e1 e2) = f $ AppE (recurse f e1) (recurse f e2)
recurse f (InfixE (Just e1) opE (Just e2)) = f $ InfixE (Just $ recurse f e1) (recurse f opE) (Just $ recurse f e2)
recurse f (InfixE (Just e1) opE Nothing) = f $ InfixE (Just $ recurse f e1) (recurse f opE) Nothing
recurse f (InfixE Nothing opE (Just e2)) = f $ InfixE Nothing (recurse f opE) (Just $ recurse f e2)
recurse f (InfixE Nothing opE Nothing) = f $ InfixE Nothing (recurse f opE) Nothing
recurse f (LamE pats e) = f $ LamE pats (recurse f e)
recurse f (TupE es) = f $ TupE $ map (recurse f) es
recurse f (CondE _ _ _) = error "recurse: undefined on CondE"
recurse f (LetE decs e) = f $ LetE (map (recurse f) decs) (recurse f e)
recurse f (CaseE e matches) = f $ CaseE (recurse f e) (map (recurse f) matches)
recurse f (DoE _) = error "recurse: undefined on DoE"
recurse f (CompE _) = error "recurse: undefined on CompE"
recurse f (ArithSeqE _) = error "recurse: undefined on ArithSeqE"
recurse f (ListE es) = f $ ListE $ map (recurse f) es
recurse f (SigE _ _) = error "recurse: undefined on SigE"
recurse f (RecConE _ _) = error "recurse: undefined on RecConE"
recurse f (RecUpdE _ _) = error "recurse: undefined on RecUpdE"
instance Reducible Dec where
recurse f (FunD _ _) = error "recurse: undefined on FunD"
recurse f (ValD pat body decs) = ValD pat (recurse f body) (map (recurse f) decs)
recurse f (DataD _ _ _ _ _) = error "recurse: undefined on DataD"
recurse f (NewtypeD _ _ _ _ _) = error "recurse: undefined on NewtypeD"
recurse f (TySynD _ _ _) = error "recurse: undefined on TySynD"
recurse f (ClassD _ _ _ _ _) = error "recurse: undefined on ClassD"
recurse f (InstanceD _ _ _) = error "recurse: undefined on InstanceD"
recurse f (SigD _ _) = error "recurse: undefined on SigD"
recurse f (ForeignD _) = error "recurse: undefined on ForeignD"
instance Reducible Body where
recurse f (GuardedB _) = error "recurse: undefined on GuardedB"
recurse f (NormalB e) = NormalB (recurse f e)
instance Reducible Match where
recurse f (Match pat body decs) = Match pat (recurse f body) (map (recurse f) decs)
simpleReduction :: Exp -> Exp
simpleReduction e@(VarE n) = e
simpleReduction e@(ConE n) = e
simpleReduction e@(LitE l) = LitE l
simpleReduction e@(AppE e1 e2) = case e1 of
LamE (p:ps) e1' -> case bindPatterns p e2 of
Just env -> reduce $ LamE ps $ reduce $ subst env e1'
Nothing -> e
otherwise -> e
simpleReduction e@(InfixE (Just e1) opE (Just e2)) = e
simpleReduction e@(InfixE _ _ _) = e
simpleReduction e@(LamE pats e') = case pats of
[] -> e'
otherwise -> e
simpleReduction e@(TupE es) = e
simpleReduction e@(CondE _ _ _) = error "simpleReduction: undefined on CondE"
simpleReduction e@(LetE decs e') = error "simpleReduction: undefined on LetE"
simpleReduction e@(CaseE e' matches) = e
simpleReduction e@(DoE _) = error "simpleReduction: undefined on DoE"
simpleReduction e@(CompE _) = error "simpleReduction: undefined on CompE"
simpleReduction e@(ArithSeqE _) = error "simpleReduction: undefined on ArithSeqE"
simpleReduction e@(ListE es) = e
simpleReduction e@(SigE _ _) = error "simpleReduction: undefined on SigE"
simpleReduction e@(RecConE _ _) = error "simpleReduction: undefined on RecConE"
simpleReduction e@(RecUpdE _ _) = error "simpleReduction: undefined on RecUpdE"
expSubst :: Env -> Exp -> Exp
expSubst env e = case lookup e env of
Just x -> x
Nothing -> e
bindPatterns :: Pat -> Exp -> Maybe Env
bindPatterns (VarP n) e = Just [(VarE n, e)]
bindPatterns (WildP) _ = Just []
bindPatterns (TupP ps) (TupE es) = if length ps /= length es
then Nothing
else do
let tupEnvs = map2 bindPatterns ps es
foldM addEnv [] tupEnvs
where map2 f as bs = map (\(a,b) -> f a b) (zip as bs)
addEnv env Nothing = Nothing
addEnv env (Just env') = Just $ env ++ env'
bindPatterns _ _ = Nothing
var x = VarE $ mkName x
pat x = VarP $ mkName x
e1 = TupE [var "a", TupE [var "b", var "c"]]
p1 = TupP [pat "p1", TupP [pat "p2", pat "p3"]]