[Haskell-cafe] Multiple State Monads

minh thu noteed at gmail.com
Mon Jan 12 15:49:50 EST 2009


2009/1/12 Phil <pbeadling at mail2web.com>:
> Hi,
>
> I've been reading the Monads aren't evil posts with interest – I'm a 2nd
> week Haskell newbie and I'm doing my best to use them where (I hope) it is
> appropriate.  Typically I'm writing my code out without using Monads
> (normally using list recursion), and then when I get them working, I delve
> into the Monad world.... This has been going well so far with a bit of help
> from you guys, but I've hit a snag.
>
> In the code below I'm using a state Monad (getEvolution), but unlike simpler
> cases I'm passing around two items of state, and one of these states is also
> ultimately a result – although I don't care about the result until I reach
> an end state.  My implementation is a bit ugly to say the least and clearly
> I'm forcing round pegs into square holes here – reading a bit online I get
> the impression that I can solve the two-state issue using Monad
> Transformers, by  wrapping a StateT around a regular State object (or even
> two StateT Monads around an Identity Monad??).  I think I understand the
> theory here, but any attempt to implement it leads to a horrible mess that
> typically doesn't compile.  The other problem of having a state that is also
> a result, I'm sure what to do about this.
>
> Was wondering if anyone could give me a push in the right direction – how
> can I rework my state monad so that it looks less wildly.
>
> Many thanks,
>
> Phil.
>
> mcSimulate :: Double -> Double -> Word64 -> [Double]
> mcSimulate startStock endTime seedForSeed = expiryStock : mcSimulate
> startStock endTime newSeedForSeed
>   where
>     expiryStock =  evalState ( do replicateM_ (truncate(endTime/timeStep)-1)
> getEvolution; getEvolution )
>                    $ (startStock,ranq1Init seedForSeed)
>     newSeedForSeed = seedForSeed + 246524
>
> discount :: Double -> Double -> Double -> Double
> discount stock r t = stock * exp (-r)*t
>
> payOff :: Double -> Double -> Double
> payOff strike stock | (stock - strike) > 0 = stock - strike
>                     | otherwise = 0
>
> -- Monad Implementation
>
> -- Yuk!
> evolveUnderlying :: (Double, Word64) -> ( Double, (Double, Word64) )
> evolveUnderlying (stock, state) = ( newStock, ( newStock, newState ) )
>   where
>     newState = ranq1Increment state
>     newStock = stock * exp ( ( ir - (0.5*(vol*vol)) )*timeStep + (
> vol*sqrt(timeStep)*normalFromRngState(state) ) )
>
> getEvolution :: State (Double, Word64) Double
> getEvolution = State evolveUnderlying

Hi,

the evolveUnderlying can simply manipulate the state, so you can

do evolveUnderlying -- state (not your state, but the tuple) changes here
   r <- gets fst -- query the state for the first element of the tuple
   return r -- simply return what you want

Note that if you want to combine your state and the stock, you simply end
with a new kind of state : the tuple (thus, no need to compose two State)

Note also, since evolveUnderlying only manipulates the internal state of the
State monad, it returns ().

Depending on how you want to structure your code, you can also use execState
instead of evalState : it returns the state on which you can use fst.

hope it helps,
Thu


More information about the Haskell-Cafe mailing list