[Haskell-cafe] Stacking State on State.....

Phil pbeadling at mail2web.com
Sun Mar 1 17:18:15 EST 2009


Thanks very much for your patient explanations - this has really helped
again!

A few final questions in-line.....

On 01/03/2009 21:46, "Daniel Fischer" <daniel.is.fischer at web.de> wrote:


> 
> One thing that helps much is to use
> 
> import Control.Monad.State.Strict
> 
> Using the default lazy State monad, you build enormous thunks in the states,
> which harms the triple stack even more than the double stack.
> With the strict State monad (and a strict left fold instead of foldr in the
> double stack), I get

Ahhh, I see.  Just to make sure I understand this the Strict version will
evaluate each state as an atomic number.  The standard lazy version will
create each state as an expression of past states... Consequentially these
will grow and grow as state is incremented?


>> 
>> type MonteCarloStateT = StateT Double
>> 
>> mc :: MonteCarloStateT BoxMullerQuasiState ()
>> mc = StateT $ \s -> do nextNormal <- generateNormal
>>                        let stochastic = 0.2*1*nextNormal
>>                        let drift = 0.05 - (0.5*(0.2*0.2))*1
>>                        let newStockSum = payOff 100 ( 100 * exp ( drift +
>> stochastic ) ) + s
>>                        return ((),newStockSum)
> 
> Don't use a new let on each line, have it all in one let-block.
> And, please, force the evaluation of newStockSum:
> 

I had looked at making this strict (along with the values in the reflect
function too), it was making a little bit of difference, but not much.  I
reckon this is because the improvement was being masked by the lazy state
monad.  Now that this is corrected, I can see it makes a big difference.

One question here tho - if we have made our State strict, will this not
result in newStockSum being atomically evaluated when we set the new state?

Also on the use of multiple 'let' statements - this has obviously completely
passed me by so far!  I'm assuming that under one let we only actually
create the newStockSum, but with 3 let statements, each is created as a
separate entity?

> 
> 
> w00t!
> 
> 

You're not joking - this is a textbook example of performance enhancement!
It's clearly something I have to keep more in mind.


>> 
>> ***************** Double Stack and Map Specific Impl:
>> 
>> 
>> iterations = 1000000
>> main :: IO()
>> main = do let normals = evalState ( evalStateT (do replicateM iterations
>> generateNormal) $ (Nothing,nextHalton) ) $ (1,[3,5])
>>           let stochastic = map (0.2*1*) normals
>>           let sde = map ((( 0.05 - (0.5*(0.2*0.2)) )*1)+) stochastic
>>           let expiryMult = map exp sde
>>           let expiry = map (100*) expiryMult
>>           let payoff = map (payOff 100) expiry
>>           let averagePO = (foldr (+) 0 payoff) / fromIntegral iterations
>>           let discountPO = averagePO * exp (-0.05)
>>           print discountPO
>> 
> 
> Same here, but important for performance is to replace the foldr with foldl'.
> 

Again I understand that foldl' is the strict version of foldl, and as we are
summing elements we can use either foldl or foldr.  I'm assuming this is
another thunk optimisation.  Does foldl not actually calculate the sum, but
moreover it creates an expression of the form a+b+c+d+e+.... Where foldl'
will actually evaluate the expression to an atomic number?

> 
> Cheers,
> Daniel



More information about the Haskell-Cafe mailing list