--
import Monad (liftM2, when) import EnvMT import StateMT import OutputMT import ExceptMT infixl 6 :*:, :/: infixl 5 :+:, :-: infixr 4 :> type Name = String type Message = String data E = E :+: E | E :-: E | E :*: E | E :/: E | Int Int | Let Name E E | Var Name | Print Message E | ReadRef Name | WriteRef Name E | E :> E eval (e1 :+: e2) = liftM2 (+) (eval e1) (eval e2) eval (e1 :-: e2) = liftM2 (-) (eval e1) (eval e2) eval (e1 :*: e2) = liftM2 (*) (eval e1) (eval e2) eval (e1 :/: e2) = liftM2 div (eval e1) $ (do x <- eval e2 when (x == 0) (raise "division by 0") return x) eval (Int x) = return x eval (Let x e1 e2) = do v <- eval e1; inModEnv ((x,v):) (eval e2) eval (Var x) = maybe (raise ("undefined variable: " ++ x)) return . lookup x =<< getEnv eval (Print x e) = do v <- eval e output (x ++ show v) return v eval (ReadRef x) = maybe (return 0) return . lookup x =<< getSt eval (WriteRef x e) = do v <- eval e updSt_ $ \s -> (x,v) : filter ((/= x) . fst) s return 0 eval (e1 :> e2) = eval e1 >> eval e2 type Heap = [(Name,Int)] type Env = [(Name,Int)] type M = WithState Heap ( WithEnv Env ( WithOutput String ( WithExcept String IO ))) run :: M a -> IO a run m = do x <- removeExcept $ listOutput $ withEnv [] $ withSt [] m case x of Left err -> error ("error: " ++ err) Right (v,o) -> mapM putStrLn o >> return v test e = print =<< run (eval e) -- examples: tests = [ Let "x" (Int 1 :/: Int 0) (Int 2) -- let is strict , ReadRef "x" -- refs are 0 by default , WriteRef "x" (Int 8) :> ReadRef "x" -- write - read , Let "x" (Int 7) $ WriteRef "x" (Int 2) :> Var "x" :*: ReadRef "x" -- vars & refs are different , Print "x before = " (ReadRef "x") -- priniting :> WriteRef "x" (Int 7) :> Print "x after = " (ReadRef "x") , Let "x" (Int 1) $ Var "x" :+: Let "x" (Int 2) (Var "x") -- nested lets ] --