
On Mon, 2011-04-11 at 12:09 +0000, Serguei Son wrote:
Consider two versions of sin wrapped: foreign import ccall "math.h sin" c_sin_m :: CDouble -> IO CDouble and foreign import ccall "math.h sin" c_sin :: CDouble -> CDouble
One can invoke them so:
mapM c_sin_m [1..n] mapM (return . c_sin) [1..n]
On my computer with n = 10^7 the first version never finishes, whereas the second one calculates the result within seconds.
To give you my context, I need to call a random variable generator multiple times, so that it must return IO a.
Any explanation for this behavior?
Simple (but possibly wrong) - the first one is always evaluated (as it might have side-effects) while the second one is left in unevaluated form (return does not force effects): (values for 2^14)
mapM c_sin_m [1..n] 1.087 s mapM (return . c_sin) [1..n] 0.021 s mapM (\x -> return $! c_sin x) [1..n] 1.160 s return $ map c_sin [1..n] 0.006 s mapM (const (return undefined)) [1..n] 0.011 s
I.e. - c_sin_m have forced evaluation so you do 10^7 times save of Haskell context (it is not marked as unsafe) and call of function - return . c_sin have not forced evaluation so you do 10^7 times wrap unevaluated value into IO To compare:
foreign import ccall unsafe "math.h sin" c_sin_um :: CDouble -> IO CDouble
foreign import ccall unsafe "math.h sin" c_sin_u :: CDouble -> CDouble
main = mapM c_sin_um [1..n] 0.028 s main = mapM (\x -> return $! c_sin_u) [1..n] 0.012 s main = mapM (return . c_sin_u) [1..n] 0.023 s
I.e. it is difference in laziness of Haskell and the making sure that function may safely call back to Haskell (which sin does not). Regards