{-# LANGUAGE FlexibleInstances #-} import Control.Monad import GHC.Base hiding ((<|>)) import Data.Map as M import Data.Maybe --------------------------------------------------- -- Monada de estado newtype State s a = State (s -> (a, s)) runState :: State s a -> (s -> (a, s)) runState (State f) = f instance Functor (State s) where fmap f (State g) = State $ \s -> let (a,s') = g s in (f a,s') instance Applicative (State s) where pure a = State $ \s -> (a, s) (State g) <*> (State k) = State $ \s -> let (f,s') = g s (a,s'') = k s' in (f a,s'') instance Monad (State s) where return a = State $ \s -> (a, s) m >>= f = State $ \s -> let (a, s') = runState m s in runState (f a) s' -- funciones sobre la monada de estado get :: State s s get = State $ \s -> (s, s) put :: s -> State s () put s = State $ \_ -> ((), s) modify :: (s -> s) -> State s () modify f = do s <- get put (f s) -- retorna el valor final de la computacion evalState :: State s a -> s -> a evalState m s = fst $ runState m s -- retorna el estado final de la computacion execState :: State s a -> s -> s execState m s = snd $ runState m s -- contar numero de operaciones en una expresion data Exp = Num Int | Add Exp Exp tick :: State Int () tick = modify (+1) evalS :: Exp -> State Int Int evalS (Num n) = return n evalS (Add e e') = do a <- evalS e b <- evalS e' tick return (a + b) -- instancia especifica de Show para ver el resultado de evalS instance Show a => Show (State Int a) where show (State ev) = "valor: " ++ show x ++ ", contador: " ++ show s where (x, s) = ev 0 nroSumas :: Exp -> Int nroSumas e = execState (evalS e) 0 -- expresiones con variables y asignacion data EXP = NUM Integer | ADD EXP EXP | VAR ID | ASSIGN ID EXP type ID = String -- evaluador eval :: EXP -> State (Map ID Integer) Integer eval (NUM n) = return n eval (ADD e e') = do v <- eval e v' <- eval e' return (v + v') eval (VAR x) = do s <- get return (fromJust $ M.lookup x s) eval (ASSIGN x e) = do v <- eval e s <- get put (insert x v s) return v -- instancia especifica de Show para ver el resultado de evalS instance Show a => Show (State (Map ID Integer) a) where show ev = "valor = " ++ show x ++ "\n" ++ "memoria = " ++ show (toList s) where (x, s) = runState ev initS initS = fromList [("x",0),("y",0),("z",0)] e1 = ASSIGN "x" (NUM 1) e2 = ASSIGN "y" (ADD (VAR "x") (NUM 2)) e3 = ASSIGN "z" (ADD e1 e2) e4 = ASSIGN "w" (ADD e3 (NUM 1))