import Control.Monad.State import Control.Monad.Identity import Control.Monad.Error data Exp = Plus Exp Exp | Minus Exp Exp | Times Exp Exp | Div Exp Exp | Const Int deriving Show answer = (Div (Div (Const 1972) (Const 2)) (Const 23)) err = (Div (Const 1) (Const 0)) -- variants of eval using standard monad transformers -- MONAD TRANSFORMES VAR 1: Error Handling type MTE a = ErrorT String Identity a evalMTE :: Exp -> MTE Int evalMTE (Div e1 e2) = do a <- evalMTE e1; b <- evalMTE e2; if b == 0 then (throwError "division by 0") else return (a `div` b) evalMTE (Const i) = return i runMTE exp = runIdentity (runErrorT (evalMTE exp)) -- MONAD TRANSFORMES VAR 2: State type MTS a = StateT Int Identity a tick :: (Num s, MonadState s m) => m () tick = do st <- get; put (st+1) evalMTS :: Exp -> MTS Int evalMTS (Div e1 e2) = do a <- evalMTS e1; b <- evalMTS e2; tick; return (a `div` b) evalMTS (Const i) = return i runMTS s exp = runIdentity ((runStateT (evalMTS exp)) s) ------------------------------ -- combining monad transformes ------------------------------ -- MONAD TRANSFORMES VAR 1+2: Error handling + State type MTES a = ErrorT String (StateT Int Identity) a evalMTES :: Exp -> MTES Int evalMTES (Div e1 e2) = do a <- evalMTES e1; b <- evalMTES e2; tick; if b == 0 then (throwError "division by 0") else return (a `div` b) evalMTES (Const i) = return i runMTES s exp = runIdentity (runStateT (runErrorT (evalMTES exp)) s) ----------------- -- Dan Piponi's examples (modified by Jan Obdrzalek) -- source: http://blog.sigfpe.com/2006/05/grok-haskell-monad-transformers.html ----------------- test1 = do a <- get modify (+1) b <- get return (a,b) test2 = do a <- get modify (++"1") b <- get return (a,b) go1 = evalState test1 0 go2 = evalState test2 "0" test3 = do (a1,a2) <- get modify (\x -> ((fst x)+1, (snd x)++"1")) (b1,b2) <- get return ((a1,b1),(a2,b2)) go3 = evalState test3 (0,"0") test4 = do modify (+ 1) lift $ modify (++ "1") a <- get b <- lift get return (a,b) go4 = runIdentity $ evalStateT (evalStateT test4 0) "0" test5 = do modify (+ 1) lift $ modify (++ "1") a <- get b <- lift get return (a,b) go5 = evalState (evalStateT test5 0) "0" test6 = do modify (+ 1) a <- get lift (print a) modify (+ 1) b <- get lift (print b) go6 = evalStateT test6 0