[Haskell-cafe] State Monad - using the updated state

Phil pbeadling at mail2web.com
Thu Jan 8 14:56:45 EST 2009


I think I've got this now - thanks to you all for the superb advice!

The reason I cannot increment state inside main is because main is not a
State monad (it's an IO monad).  Thus in order to use my State Monad, I have
execute inside a State monad as that the state is encapsulated in there.

I'll have to have a think about how I'm going to structure the rest of my
code inside something like Ryan's randomComputation example - the basic
example works perfectly!  I'm writing a Monte Carlo simulator for financial
portfolios - it's something I've done in several languages so I often use it
to test drive a new language.  Most imperative implementations of this sort
thing are very state-heavy, so I thought it would fun to re-think it a bit
in Haskell.

My initial thoughts before delving into Monads was to take advantage of
Haskell's lazy evaluation and create an 'infinite' list of randoms using
something like the below:

ranq1List :: (Word64 -> a ) -> Word64 -> [a]
ranq1List converter state = converter newState : ranq1List converter
newState
  where
    newState = ranq1Increment state

This works fine - the converter is an extra parameter that carrys a
partially defined function used to numerically translate from
word64->whatever_type__we_want as stipulated in Numerical Recipes' C++
example.  It was at this point I felt it was getting a bit ugly and started
to look at Monads (plus I wanted to see what all 'fuss' was about with
Monads too!).

One more question on this - the other concern I had with the recursive list
approach was that although lazy evaluation prevents me generating numbers
before I 'ask' for them, I figured that if I was going to be asking for say
10 million over the course of one simulation, that although I request them
one by one, over hours or even days, at the end of the simulation I will
still have a list of 10 million word64s - each of which I could throw away
within minutes of asking for it.  This seemed like huge memory bloat, and
thus probably I was taking the wrong approach.

I'd be interested to know if you have any thoughts on the various solutions?
Ryan's randomComputation strikes me as the most practical and there's an old
adage that if a language provides a facility (i.e. The State Monad here),
you shouldn't be rewriting similar functionality yourself unless there is a
very very good reason to go it alone.  Thus I figure that Haskell's State
Monad used as described is always going to beat anything I come up with to
do the same thing - unless I spend an awful lot of time tailoring a specific
solution.

If you think there is a nicer non-Monadic, pure solution to this type of
problem, I'd be interested to hear them.

Thanks again for all your help,

Phil.



On 08/01/2009 13:27, "Kurt Hutchinson" <kelanslists at gmail.com> wrote:

> Ryan gave some great advice about restructuring your program to do
> what you want, but I wanted to give a small explanation of why that's
> necessary.
> 
> 2009/1/7 Phil <pbeadling at mail2web.com>:
>>  I want to be able to do:
>> 
>> Get_a_random_number
>> 
>> < a whole load of other stuff >
>> 
>> Get the next number as defined by the updated state in the first call
>> 
>> <some more stuff>
>> 
>> Get another number, and so on.
> 
> The issue you're having is that you're trying to do the "other stuff"
> in your 'main', but main isn't inside the State monad. The only State
> computation you're calling from main is getRanq1, but you really need
> another State computation that does "other stuff" and calls getRanq1
> itself. That's what Ryan's first suggestion implements. You need all
> your "other stuff" to be done inside the State monad so that it has
> read/update access to the current random state. So all your main does
> is run a State computation. That computation calls getRanq1 itself and
> then "other stuff" in between calls to getRanq1.
> 
> Does that make sense?
> 
> Kurt



More information about the Haskell-Cafe mailing list