[Haskell-cafe] Foreign function performance: monadic vs pure
Maciej Marcin Piechotka
uzytkownik2 at gmail.com
Mon Apr 11 15:14:13 CEST 2011
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
More information about the Haskell-Cafe
mailing list