Reputation: 185
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
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
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