Search code examples
haskellfunctional-programmingmonadsstate-monad

State Monad Bind


I think I understand how the State Monad works. I've managed to write some code which uses the State Monad.

I understand how the Monad instance of State works:

instance Monad (State s) where  
return x = State $ \s -> (x,s)  
(State h) >>= f = State $ \s -> let (a, newState) = h s  
                                    (State g) = f a  
                                in  g newState  

This code works perfectly fine:

type PeopleStack = [String]

enterClub :: String -> State PeopleStack String
enterClub name = state $ \xs -> (name ++ " entered club", name:xs)

leaveClub :: State PeopleStack String
leaveClub = state $ \(x:xs) -> ("Someone left the club", xs)

clubAction :: State PeopleStack String
clubAction = do
  enterClub "Jose"
  enterClub "Thais"
  leaveClub
  enterClub "Manuel"

However when I try to write clubAction in a bind function I can't seem to get it working.

this is what I have tried:

let statefulComputation1 = enterClub "Jose"
statefulComputation1 :: State PeopleStack String

runState (statefulComputation1 >>= (enterClub "Manuel") >>= leaveClub) [] 

I get this error:

<interactive>:13:22:
Couldn't match type ‘StateT
                       PeopleStack Data.Functor.Identity.Identity String’
               with ‘String
                     -> StateT PeopleStack Data.Functor.Identity.Identity a’
Expected type: String
               -> StateT PeopleStack Data.Functor.Identity.Identity a
  Actual type: State PeopleStack String
Relevant bindings include
  it :: (a, PeopleStack) (bound at <interactive>:13:1)
In the second argument of ‘(>>=)’, namely ‘leaveClub’
In the first argument of ‘runState’, namely
  ‘(state1 >>= leaveClub)’

My question is how do I translate that do notation to a function using bind.


Solution

  • You need to use (>>) instead of (>>=):

    runState (statefulComputation1 >> (enterClub "Manuel") >> leaveClub) []
    

    (enterClub "Manuel") has type State PeopleStack String while (>>=) requires a function String -> State PeopleStack a as its second argument. Since you don't use use the result from statefulComputation1 you can combine them with (>>) which ignores the result from the first state computation.