{-# LANGUAGE FlexibleContexts, TypeApplications #-} import Control.Monad.State import Control.Monad.Except import Control.Monad.Trans.Maybe import Data.Map as M import Data.Maybe -- arbol de sintaxis abstracta de las expresiones data Exp = Num Int | Add Exp Exp | Div Exp Exp | Var ID | Assign ID Exp deriving Show type ID = String -- evaluador generico en terminos de MonadError y MonadState -- requiere la flag FlexibleContexts eval :: (MonadError () m, MonadState (Map ID Int) m) => Exp -> m Int eval (Num n) = return n eval (Add x y) = do a <- eval x b <- eval y return (a + b) eval (Var v) = do s <- get -- retorna cero si la variable no existe return (fromMaybe 0 $ M.lookup v s) eval (Assign v x) = do a <- eval x s <- get put (insert v a s) return a eval (Div x y) = do a <- eval x b <- eval y if b==0 then throwError () else return (a `div` b) -- corremos el evaluador con una monada especifica M, resultante de aplicar -- el transformador StateT a la monada Maybe: type M a = StateT (Map ID Int) Maybe a -- dada una expresión e, (eval e) computa algo de tipo M Int -- que corresponde a algo de la forma: s -> Maybe (Int,s), siendo s = Map ID Int -- evaluamos comenzando con el estado vacio y descartamos el estado final run :: Exp -> Maybe Int run e = evalStateT (eval e) empty -- version alternativa donde aplicamos el transformador ExceptT a la monada State type M' a = ExceptT () (State (Map ID Int)) a -- luego convertimos la computacion en ExceptT a una computacion en MaybeT -- para que retorne algo de tipo Maybe en lugar de Either -- corresponde a algo de la forma: s -> (Maybe Int,s), siendo s = Map ID Int run' :: Exp -> Maybe Int run' e = evalState (seval e) empty where -- comenzamos a instanciar la monada concreta eeval :: MonadState (Map ID Int) m => Exp -> ExceptT () m Int eeval = eval -- convertimos ExceptT a MaybeT (para retornar un Maybe) meval :: MonadState (Map ID Int) m => Exp -> MaybeT m Int meval = exceptToMaybeT . eeval -- quitamos constructor MaybeT e instanciamos la monada m como State seval :: Exp -> State (Map ID Int) (Maybe Int) seval = runMaybeT . meval