[Haskell-cafe] Multiple State Monads

David Menendez dave at zednenem.com
Tue Jan 13 19:56:53 EST 2009

On Tue, Jan 13, 2009 at 5:29 PM, Phil <pbeadling at mail2web.com> wrote:
> Many thanks for the replies.
> Using 'modify' cleans the syntax up nicely.
> With regard to using 'iterate' as shown by David here:
>>> mcSimulate :: Double -> Double -> Word64 -> [Double]
>>> mcSimulate startStock endTime seedForSeed = fst expiryStock : mcSimulate
>>> startStock endTime newSeedForSeed
>>>  where
>>>    expiryStock = iterate evolveUnderlying (startStock, ranq1Init seedForSeed)
>>> !! truncate (endTime/timeStep)
>>>    newSeedForSeed = seedForSeed + 246524
> My only concern with using this method is - Will 'iterate' not create a full
> list of type [Double] and then take the final position once the list has
> been fully realized?

iterate creates the elements of the list as they are requested, and !!
will discard everything until it hits the answer it wants. That being
said, it's not the best way to repeatedly apply a function, as Luke
pointed out. A better way would probably be something like this,

    applyNTimes :: Int -> (a -> a) -> a -> a
    applyNTimes n f a
        | n <= 0    = a
        | otherwise = applyNTimes (n-1) $! f a

That ($!) is there to make sure "f a" gets evaluated before calling
applyNTimes again.

> The key reason for using the Monad was to tell Haskell to discard all but
> the current state.  If I'm wrong about please let me know, as I don't want
> to be guilty of overcomplicating my algorithm, and more importantly it means
> I'm not yet totally grasping the power of Haskell!

I'm not entirely sure what you mean by "discard all but the current
state", but Haskell implementations are pretty good about discarding
values that are no longer needed.

That being said, here's one way I might implement your algorithm. It's
a sketch, and I haven't tested it, but the general idea should be

    mcSimulate stock endTime seed = map (evolve n stock) $ iterate
(+246524) seed
        n = truncate (endTime / timeStep)

    evolve :: Int -> Double -> Word64 -> Double
    evolve n stock seed
        | n <= 0    = stock
        | otherwise = evolve (n-1) (evolveStock stock seed)
(ranq1Increment seed)

    evolveStock :: Double -> Word64 -> Double
    evolveStock stock seed = stock * exp (a + b * normalFromRngState seed)
        a = (ir - 0.5 * vol * vol) * timeStep
        b = vol * sqrt timeStep

Dave Menendez <dave at zednenem.com>

More information about the Haskell-Cafe mailing list