Davido Widre
Davido Widre

Reputation: 185

Increment function for state monad in Haskell

I have the following defined State Monad, with which I am trying to implement an increment function:

data State a = State (Int -> (a, Int))

instance Monad State where
  return x = State $ \s -> (x, s)

  (State f) >>= k = State $ \s ->
    let
      (x, s') = f s
      State f' = k x
    in f' s'

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

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

I have done the following:

increment :: State ()
increment = do
  a <- get
  put(a+1)

And this appears to work.

Is this correct, and how can I verify that the state is indeed being incremented? Perhaps more generally, how do I use get an put?

Upvotes: 2

Views: 1055

Answers (2)

Luis Casillas
Luis Casillas

Reputation: 30237

Let's add a few utility functions to this code:

-- Given a `State` computation and a starting state, run the computation
-- and obtain the result value and final state.
runState :: State a -> Int -> (a, Int)
runState (State f) init = f init

-- Given a `State` computation and a starting state, run the computation
-- and obtain the result value.
evalState :: State a -> Int -> a
evalState st i = fst (runState st i)

-- Given a `State` computation and a starting state, run the computation
-- and obtain the final state.
execState :: State a -> Int -> Int
execState st i = snd (runState st i)

Now, using one of these functions, how would you write a function that tests whether increment does in fact increment the state by one?

Upvotes: 1

cocreature
cocreature

Reputation: 811

You need some way to extract the inner function of the state. You can either do this by pattern matching on State a like you do in your bind definition or you can define State using record syntax data State a = State {runState :: Int -> (a, Int)}. Once you have runState you can easily test your increment function using runState increment 1. Your use of get and put seems to be just fine, not quite sure what you want to know there.

Also you should add an Applicative instance for State because Applicative will be a superclass of Monad as of ghc 7.10.

Upvotes: 1

Related Questions