Use a state monad to track environment.

Within the Rename module, switch to using the state
monad to track renamed variables (and the GUID
numbering). This allows rename' and other functions
to be much simpler by removing the additional `env`
argument.
This commit is contained in:
Abhinav Gupta 2012-04-27 21:16:01 -07:00
parent 5a11ed42a7
commit 8fbfbce801

View file

@ -2,96 +2,95 @@
module Rename (rename) where
import Ast
import Control.Arrow (first)
import Control.Monad (ap, liftM, foldM, mapM, Monad)
import Control.Monad (ap, liftM, mapM, Monad)
import Control.Monad.State (evalState, State, get, put)
import Data.Char (isLower)
import Data.Maybe (fromMaybe)
-- Wrapper around State monad.
newtype GuidCounter a = GC { runGC :: State Int a }
data Env = Env { guidCount :: Int
, environment :: [(String, String)] }
deriving (Show)
newtype Environment a = E { runE :: State Env a }
deriving (Monad)
-- Get the next GUID, incrementing the counter.
guid :: GuidCounter Int
guid = GC $ do n <- get
put (n + 1)
return n
-- Generate a new name for x.
envExtend :: String -> Environment String
envExtend x = E $ do env <- get
let guid = guidCount env
e = environment env
newX = x ++ "_" ++ show guid
put $ env { guidCount = guid + 1
, environment = (x, newX):e }
return newX
-- Get the name to use for x. If x was renamed, the new name will be used,
-- otherwise, the oringal name.
envLookup :: String -> Environment String
envLookup x = E $ get >>= return . fromMaybe x . lookup x . environment
rename :: Expr -> Expr
rename expr = evalState (runGC $ rename' id expr) 0
rename expr = evalState (runE $ rename' expr) $ Env { guidCount = 0
, environment = [] }
rename' :: (String -> String) -> Expr -> GuidCounter Expr
rename' env expr =
case expr of
Range e1 e2 -> Range `liftM` rnm e1
`ap` rnm e2
Access e x -> Access `liftM` rnm e
`ap` return x
rename' :: Expr -> Environment Expr
Binop op@(h:_) e1 e2 ->
let rop = if isLower h || '_' == h
then env op
else op
in Binop rop `liftM` rnm e1
`ap` rnm e2
rename' (Range e1 e2) = Range `liftM` rename' e1
`ap` rename' e1
Lambda x e -> do
(rx, env') <- extend env x
Lambda rx `liftM` rename' env' e
rename' (Access e x) = Access `liftM` rename' e
`ap` return x
App e1 e2 -> App `liftM` rnm e1
`ap` rnm e2
rename' (Binop op e1 e2) = Binop `liftM` resolveOp op
`ap` rename' e1
`ap` rename' e2
where resolveOp op@(h:_)
| isLower h || '_' == h = envLookup op
| otherwise = return op
If e1 e2 e3 -> If `liftM` rnm e1
`ap` rnm e2
`ap` rnm e3
rename' (Lambda x e) = Lambda `liftM` envExtend x
`ap` rename' e
Lift e es -> Lift `liftM` rnm e
`ap` mapM rnm es
rename' (App e1 e2) = App `liftM` rename' e1
`ap` rename' e2
Fold e1 e2 e3 -> Fold `liftM` rnm e1
`ap` rnm e2
`ap` rnm e3
rename' (If e1 e2 e3) = If `liftM` rename' e1
`ap` rename' e2
`ap` rename' e3
Async e -> Async `liftM` rnm e
rename' (Lift e es) = Lift `liftM` rename' e
`ap` mapM rename' es
Let defs e -> do
let (vs,es) = unzip defs
env' <- foldM (\acc x -> snd `liftM` extend acc x) env vs
es' <- mapM (rename' env') es; re <- rename' env' e
return $ Let (zip (map env' vs) es') re
rename' (Fold e1 e2 e3) = Fold `liftM` rename' e1
`ap` rename' e2
`ap` rename' e3
Var x -> return . Var $ env x
rename' (Async e) = Async `liftM` rename' e
Data name es -> Data name `liftM` mapM rnm es
rename' (Let defs e) = Let `liftM` mapM letF defs
`ap` rename' e
where letF (x, exp) = do x' <- envExtend x
exp' <- rename' exp
return (x', exp')
Case e cases -> Case `liftM` rnm e
`ap` mapM (patternRename env) cases
rename' (Var x) = Var `liftM` envLookup x
_ -> return expr
rename' (Data name es) = Data name `liftM` mapM rename' es
where rnm = rename' env
rename' (Case e cases) = Case `liftM` rename' e
`ap` mapM patternRename cases
extend :: (String -> String) -> String -> GuidCounter (String, String -> String)
extend env x = do
n <- guid
let rx = x ++ "_" ++ show n
return (rx, \y -> if y == x then rx else env y)
rename' e = return e
patternExtend :: Pattern -> (String -> String) -> GuidCounter (Pattern, String -> String)
patternExtend pattern env =
case pattern of
PAnything -> return (PAnything, env)
PVar x -> first PVar `liftM` extend env x
PData name ps ->
first (PData name . reverse) `liftM` foldM f ([], env) ps
where f (rps,env') p = do (rp,env'') <- patternExtend p env'
return (rp:rps, env'')
patternRename :: (String -> String) -> (Pattern, Expr) -> GuidCounter (Pattern, Expr)
patternRename env (p,e) = do
(rp,env') <- patternExtend p env
re <- rename' env' e
return (rp,re)
patternExtend :: Pattern -> Environment Pattern
patternExtend PAnything = return PAnything
patternExtend (PVar x) = PVar `liftM` envExtend x
patternExtend (PData name ps) = PData name `liftM` mapM patternExtend ps
patternRename :: (Pattern, Expr) -> Environment (Pattern, Expr)
patternRename (p, e) = do newP <- patternExtend p
newE <- rename' e
return (p, e)