J. Doe
J. Doe

Reputation: 3

Monad State And get function

type InterpreterMonad  = StateT (Env, Env) (ErrorT String IO ) ()    

interpreter :: Stmts -> InterpreterMonad
interpreter (Statements s EmptyStmts) = interpreteStmt s
interpreter (Statements s stmts) = interpreteStmt s >>= \m -> (interpreter stmts)


-- definicja funkcji

interpreteStmt :: Stmt -> InterpreterMonad 
interpreteStmt (DefFun  (VarName name) args typ begin statements end) = get >>= 
    \(envOut, (sInnerEnvFun, sInnerEnvEVal)) -> case (Map.lookup (VarName name) sInnerEnvFun) of
        Nothing -> put ( ( envOut, ((Map.insert (VarName name) (DefFun  (VarName name) args typ begin statements end) sInnerEnvFun), sInnerEnvEVal)) ) >>= \_ -> return ()
        (Just x) -> throwError  "ee"

Hi, I cannot understand why get and put functions can be called? How the Haskell know "where" is state? I have a problem in favour of imperative programming- after all, such function we have to call on object ( as method) or pass state by argument.

Upvotes: 0

Views: 146

Answers (2)

Luis Casillas
Luis Casillas

Reputation: 30237

The State type (which StateT is a generalization of) is implemented something like this:

newtype State s a = 
    State { -- A function that takes a state of type `s` and 
            -- produces a pair `(a, s)` of a result of type 
            -- `a` and a new state of type `s`.
            runState :: s -> (a, s) 
          }

This type has instances for Functor, Applicative and Monad that allow you to assemble complex State values out of simpler ones:

-- I won't write the code for these here
instance Functor (State s) where ...
instance Applicative (State s) where ...
instance Monad (State s) where ...

Basically, State is a shortcut for chaining functions of types that look like s -> (a, s), but without having to pass around those s values explicitly. When you're ready to actually "feed" a State action with an s value you use one of these operations (depending on which part of the result you want):

runState  :: State s a -> s -> (a, s)
evalState :: State s a -> s -> a
execState :: State s a -> s -> s

What put and get do, then, is interact with the "hidden" state argument that the State type implicitly passes around in your code. Their implementations are something like this:

get :: State s s
get = State (\s -> (s, s))

put :: s -> State s ()
put s = State (\_ -> ((), s))

And that's it!

Upvotes: 1

Rein Henrichs
Rein Henrichs

Reputation: 15605

When you use the State monad functions get and put and sequence them with do notation or >>=, you are constructing a "recipe" (often called an "action") for accessing and modifying local state that will eventually be used with some particular state. For example:

increment = do
  count <- get
  put (count + 1)

This action can then be used with the part of the State interface that lets you run actions by passing in a state. We will use execState, which returns the state and discards the other value, to demonstrate:

> execState increment 1
2

execState is what connects the action increment with the state it modifies. increment by itself doesn't contain any state, it is just a recipe for interacting with state that you must evaluate later.

Upvotes: 1

Related Questions