I know very little about profiling, but your comment about spending a lot of time garbage collecting rang a bell with me - the example on RWH talks about that exact issue. Thus, I would recommend walking through the profiling techniques described on <a href="http://book.realworldhaskell.org/read/profiling-and-optimization.html">http://book.realworldhaskell.org/read/profiling-and-optimization.html</a> .<br>
<br><div class="gmail_quote">On Sun, Mar 1, 2009 at 3:03 PM, Phil <span dir="ltr">&lt;<a href="mailto:pbeadling@mail2web.com">pbeadling@mail2web.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi,<br>
<br>
Thanks for the replies - I haven&#39;t had a chance to try out everything<br>
suggested yet - but your explanations of transformers nailed it for me.<br>
<br>
However, in terms of performance when stacking, I&#39;ve come across something<br>
I&#39;m struggling to explain - I was wondering if anyone could offer up and<br>
explanation.<br>
I&#39;ve rewritten my code twice - one with 3 stacked monads, and one with 2<br>
stacked monads and a load of maps.  Heuristically I would have thought the 3<br>
stacked monads would have performed as well, or even better than the 2<br>
stacked solution, but the 2 stacked solution is MUCH faster and MUCH less<br>
memory is used.  They are both using 90% of the same code and both chain<br>
together the same number of computations using replicateM.  From profiling I<br>
can see that the pure function &#39;reflect&#39; takes up most of the umph in both<br>
cases - which I&#39;d expect.  But in the triple stacked version the garbage<br>
collector is using up &gt;90% of the time.<br>
<br>
I&#39;ve tried using BangPatterns to reduce memory usage in the Triple Stack<br>
version - doing this I can half the time it takes, but it is still running<br>
at over twice the time of the two stack version.  The BangPatterns were also<br>
put in Common Code in the reflect function - so I&#39;d expect both solutions to<br>
need them?<br>
<br>
Even though both pieces of code are a bit untidy, the triple stacked monad<br>
&#39;feels&#39; nicer to me - everything is encapsulated away and one evaluation in<br>
main yields the result.  From purely a design perspective I prefer it - but<br>
obviously not if it runs like a dog!<br>
<br>
Any ideas why the triple stack runs so slow?<br>
<br>
Thanks again!<br>
<br>
Phil<br>
<br>
***************** Triple Stack Specific Impl:<br>
<br>
type MonteCarloStateT = StateT Double<br>
<br>
mc :: MonteCarloStateT BoxMullerQuasiState ()<br>
mc = StateT $ \s -&gt; do nextNormal &lt;- generateNormal<br>
                       let stochastic = 0.2*1*nextNormal<br>
                       let drift = 0.05 - (0.5*(0.2*0.2))*1<br>
                       let newStockSum = payOff 100 ( 100 * exp ( drift +<br>
stochastic ) ) + s<br>
                       return ((),newStockSum)<br>
<br>
iterations = 1000000<br>
main :: IO()<br>
main = do let sumOfPayOffs = evalState ( evalStateT ( execStateT (do<br>
replicateM_ iterations mc) $ 0 ) $ (Nothing,nextHalton) ) $ (1,[3,5])<br>
          let averagePO = sumOfPayOffs / fromIntegral iterations<br>
          let discountPO = averagePO * exp (-0.05)<br>
          print discountPO<br>
<br>
<br>
***************** Double Stack and Map Specific Impl:<br>
<br>
<br>
iterations = 1000000<br>
main :: IO()<br>
main = do let normals = evalState ( evalStateT (do replicateM iterations<br>
generateNormal) $ (Nothing,nextHalton) ) $ (1,[3,5])<br>
          let stochastic = map (0.2*1*) normals<br>
          let sde = map ((( 0.05 - (0.5*(0.2*0.2)) )*1)+) stochastic<br>
          let expiryMult = map exp sde<br>
          let expiry = map (100*) expiryMult<br>
          let payoff = map (payOff 100) expiry<br>
          let averagePO = (foldr (+) 0 payoff) / fromIntegral iterations<br>
          let discountPO = averagePO * exp (-0.05)<br>
          print discountPO<br>
<br>
<br>
***************** Common Code Used By Both Methods:<br>
<br>
<br>
import Control.Monad.State<br>
import Debug.Trace<br>
<br>
-- State Monad for QRNGs - stores current iteration and list of<br>
-- bases to compute<br>
type QuasiRandomState = State (Int,[Int])<br>
<br>
nextHalton :: QuasiRandomState [Double]<br>
nextHalton = do (n,bases) &lt;- get<br>
                let !nextN = n+1<br>
            put (nextN,bases)<br>
            return $ map (reflect (n,1,0)) bases<br>
<br>
type ReflectionThreadState = (Int,Double,Double)<br>
<br>
reflect :: ReflectionThreadState -&gt; Int -&gt; Double<br>
reflect (k,f,h) base<br>
  | k &lt;= 0 = h<br>
  | otherwise = reflect (newK,newF,newH) base<br>
      where<br>
        newK = k `div` base<br>
        newF = f / fromIntegral base<br>
        newH = h + fromIntegral(k `mod` base) * newF<br>
<br>
-- So we are defining a state transform which has state of &#39;maybe double&#39;<br>
and an<br>
-- operating function for the inner monad of type QuasiRandomMonad returning<br>
a [Double]<br>
-- We then say that it wraps an QuasiRandomMonad (State Monad) - it must of<br>
course<br>
-- if we pass it a function that operates on these Monads we must wrap the<br>
same<br>
-- type of Monad.  And finally it returns a double<br>
<br>
type BoxMullerStateT = StateT (Maybe Double, QuasiRandomState [Double])<br>
type BoxMullerQuasiState = BoxMullerStateT QuasiRandomState<br>
<br>
generateNormal :: BoxMullerQuasiState Double<br>
generateNormal = StateT $ \s -&gt; case s of<br>
                (Just d,qrnFunc) -&gt; return (d,(Nothing,qrnFunc))<br>
                (Nothing,qrnFunc) -&gt; do qrnBaseList &lt;- qrnFunc<br>
                                    let (norm1,norm2) = boxMuller (head<br>
qrnBaseList) (head $ tail qrnBaseList)<br>
                                    return (norm1,(Just norm2,qrnFunc))<br>
<br>
boxMuller :: Double -&gt; Double -&gt; (Double,Double)<br>
-- boxMuller rn1 rn2 | trace ( &quot;rn1 &quot; ++ show rn1 ++ &quot; rn2 &quot; ++ show rn2 )<br>
False=undefined<br>
boxMuller rn1 rn2 = (normal1,normal2)<br>
  where<br>
    r        = sqrt ( (-2)*log rn1)<br>
    twoPiRn2 = 2 * pi * rn2<br>
    normal1  = r * cos ( twoPiRn2 )<br>
    normal2  = r * sin ( twoPiRn2 )<br>
<br>
<br>
<br>
payOff :: Double -&gt; Double -&gt; Double<br>
payOff strike stock | (stock - strike) &gt; 0 = stock - strike<br>
                    | otherwise = 0<br>
<div class="Ih2E3d"><br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
On 28/02/2009 13:31, &quot;Daniel Fischer&quot; &lt;<a href="mailto:daniel.is.fischer@web.de">daniel.is.fischer@web.de</a>&gt; wrote:<br>
<br>
&gt; Am Samstag, 28. Februar 2009 13:23 schrieb Phil:<br>
&gt;&gt; Hi,<br>
&gt;&gt;<br>
&gt;&gt; The problem is ­ HOW DO I WRAP ANOTHER INDEPENDENT STATE AROUND THIS?<br>
&gt;&gt;<br>
&gt;&gt; After some googling it looked like the answer may be Monad Transformers.<br>
&gt;&gt; Specifically we could add a StateT transform for our Box Muller state to<br>
&gt;&gt; our VanDerCorput State Monad.<br>
&gt;&gt; Google didnąt yield a direct answer here ­ so Iąm not even sure if my<br>
&gt;&gt; thinking is correct, people describe the process of using a transform as<br>
&gt;&gt; Śwrapping one monad in anotherą or Śthreading one monad into anotherą.<br>
&gt;&gt; What we want to do is have some internal state controlled by an independent<br>
&gt;&gt; outer state -  this sounds about right to me?<br>
&gt;<br>
&gt; If you absolutely don&#39;t want to have a state describing both, yes.<br>
&gt;<br>
&gt;&gt;<br>
<br>
</div>&lt;SNIP&gt;<br>
<br>
</blockquote></div><br>