2008/5/19 Dmitri O.Kondratiev <[EMAIL PROTECTED]>: > I am trying to understand State monad example15 at: > http://www.haskell.org/all_about_monads/html/statemonad.html > > Hi Dmitri,
I'm not sure you need to understand everything about Monad and do-notation to use the State Monad. So I will try to explain its use without talking about those scary topics. ;-) In Haskell you use the state monad when you want to hide state passing between function calls. As Haskell is pure you cannot change state. You can just create a new state and return it along with the value. In haskell you would do this by returning the value and new state in a tuple. State passing functions usually have the type `s -> (a, s)` where a is the type of the return value and s is the type of the State. This is exactly what the `random` function does. It gets a state and returns a tuple made of a value and a new state (StdGen: is a new seed for the random generator) to be used on the next `random` function call . Without the state monad you have to explicitely pass the new seed between calls to `random` as using the same seed for all function calls would always give you the same "not so random" number. Explicit state passing would look like this. get3RandomInts :: StdGen -> (Int, Int, Int) get3RandomInts g1 = let (r1, g2) = random g1 (r2, g3) = random g2 (r3, _) = random g3 in (r1, r2, r3) It's tedious, unreadable and error prone as it's easy to mess up the numbering (based on my experience). The State Monad allow you to hide the state passing. You don't have to give the state as an argument and your function won't return a changed state along with the data. Code running in the State Monad will look like this: getAny :: (Random a) => State StdGen a getAny = do g <- get -- magically get the current StdGen let (x, g') = random g put g' -- magically save the new StdGen for later return x get3RandomIntsWithState :: State StdGen (Int, Int, Int) get3RandomIntsWithState = do r1 <- getAny -- you don't care about stdgen passing r2 <- getAny r3 <- getAny return (r1, r2, r3) To use your get3RandomIntsWithState function you need to run it using one of runState (returns the (value, state)) or evalState (returns the value). main :: IO () main = do g <- getStdGen let t = evalState get3RandomsWithState g print t The interesting bits are in the getAny function. The State Monad provides you with 2 new function, get and set. If you look at this function as blackboxes; `get` will retrieve the current State and `put` will save a new State. You don't need to worry about how the State is passed from one getAny function call to another as long as they're run in the same `evalState` call. Now getAny can be simplified. If you look at the random function and at the State newtype declaration you will see that a State is a `s -> (a, s)` function "hidden" in the State constructor. newtype State s a = State {runState :: s -> (a, s)} random is also of the type `s -> (a, s)` even if variables are labelled `g` and `a` random :: (RandomGen g, Random a) => g -> (a, g) So wrapping the random function into the State constructor will just give you a getAny function for free. getAny :: (Random a) => State StdGen a getAny = State random I put a copy of the code in http://hpaste.org/7768 In short to use the State monad, you just need to care about a couple of details. The type of your functions running in the State Monad must end in `State s a` where `s` is the type of the state and `a` the type of the return value. You have to run it using either runState, execState or evalState. runState will return both the value and the state, execState will return the state and evalState will return just the value. You must use put and get to retrieve and store the State but don't need to care about the details of how the state is passed. As long as your function calls are all part of the same action. I hope it helps. I'm also quite new at Haskell and the terminology used is probably not very accurate. Best regards, Olivier.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe