Baojun Wang wangbj at gmail.com
Fri Jul 3 08:18:55 UTC 2015

```Hi,

First of all, I found it interesting that

loopM_ f k n s = when (k <= n) (f k >> loopM_ f (s+k) n s)

loopM_ seems faster than mapM_    ( mapM_ f [k, k+s..n]))

I think mapM_ is used very commonly, why it's performance is even lower
than a hand-written loop function?

2nd, even I replace mapM_ with loopM_ from above, when chain IO action, it
still can leak space. ( Because IO Monad (>>) need keep ``RealWorld s''
updated so that I/O actions can be done in-order? )

Consider below function:

f3 :: UArray Int Int -> IOUArray Int Int64 -> Int -> IO ()
f3 u r i = let !v = u ! i
in go (f31 v) i i
where f31 v j = readArray r j >>= \v1 ->
writeArray r j (v1 + (fromIntegral i) * (fromIntegral v))
f31 :: Int -> Int -> IO ()
go g k s = when (k <= maxn) (
g k >> go g (s+k) s )

When call f3:

loopM_ (f3 uu res) 1 1 1000000

Which will have blow profiling output:

individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc

...
loopM_ Main 104 4000002 7.4 10.1 100.0 99.3
f3 Main 113 1000000 1.0 2.0 70.2 69.1
f3.go Main 116 14970034 32.7 67.1 68.8 67.1
f3.f31 Main 117 13970034 34.5 0.0 36.1 0.0
f3.f31.\ Main 118 13970034 1.7 0.0 1.7 0.0
f3.f31 Main 114 0 0.3 0.0 0.4 0.0
f3.f31.\ Main 115 0 0.1 0.0 0.1 0.0
...
Why f3.go consumes so much space (67.1%)? The only reason I can think of is
IO Monad chain (>>) isn't space free as I thought.

Did I get something fundamentally wrong?

Thanks
baojun
-------------- next part --------------
An HTML attachment was scrubbed...