[Haskell-cafe] Newbie: State monad example questions

Olivier Boudry olivier.boudry at gmail.com
Thu May 22 09:49:54 EDT 2008


On Wed, May 21, 2008 at 6:19 PM, Dmitri O.Kondratiev <dokondr at gmail.com>
wrote:


> -- Then we can use  this State object (returned by getAny) in a function
> generating random values such as:
>
> makeRnd :: StdGen -> (Int, StdGen)
> makeRnd = runState (do
>                       y <- getAny
>                       return y)
>

You can simplify this:

do y <- m
    return y

is equivalent to

`do m`

or `m`

According to Monad Laws.

So you could write the same code as:
makeRnd = runState getAny

In that case, the use of the State Monad is not really interesting as you
just replaced a call to `random g` with a call to `runState getAny g`. The
State Monad is interesting if you have more than one action in the first
argument of the `runState` function because the state passing will only work
in a single `State s a`.

Thomas Hartman asked for use cases so I will describe  programs I used the
State Monad for:

1) You can find a portion of the code here: http://hpaste.org/7809

The purpose of this program was extracting address parts (PO box, street,
city, country, postal code, ...) from addresses which are composed of a
name, 3 free text lines and a zip code. The state is a list of AddressPart
elements. If you look at the extractAddress function, it contains many other
function running in the State Monad. Each function can get and put the
state. The state will contain both unparsed and already parsed AddressPart
elements.

The big benefit I got from using the State Monad was that I was able to
reorder the functions by just copy/pasting the function name from one place
to another.

Each of the `State Address ()` function will get the state, try to find an
address part in the unparsed AddressPart elements and put a new State with
the recognized AddressPartS if any.

I think parsing is a common use case for the State Monad where you want to
store the unparsed data along with the parse result and don't want to care
about passing those elements from one function to another.

2) I also recently used the State Monad Transformer to build a single
Data.Map from a set of different files. The State is the Data.Map and the
action in the runStateT is a mapM_ over a list of file names.

processFile :: String -> StateT (PartsMap B.ByteString) IO ()
-- get the Map
-- add the file info
-- put the Map

runStateT (mapM_ processFile fileNames) M.Empty
-- each processFile call will get access to the result of the previous call
and put the updated Map.

I don't know if it's a common use case for the State Monad, but I found it
useful. I could probably have used foldM to achieve the same goal and don't
worry about using the State Monad.

Best regards,

Olivier.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20080522/81824ea7/attachment.htm


More information about the Haskell-Cafe mailing list