[Haskell-cafe] The implementation of Control.Exception.bracket
Max Bolingbroke
batterseapower at hotmail.com
Mon Jan 31 16:06:14 CET 2011
On 31 January 2011 14:17, Leon Smith <leon.p.smith at gmail.com> wrote:
> Is there some subtle semantic difference? Is there a performance
> difference? It seems like a trivial thing, but I am genuinely
> curious.
According to my understanding the two should have equivalent
semantics. As for performance, I whipped up a trivial Criterion
microbenchmark and the version that doesn't use "finally" seems to
consistently benchmark 32ns (33%) faster than the version that does
use it, likely because it avoids a useless mask/restore pair.
(Note that this result is reversed if you compile without -O2, I guess
because -O2 optimises the library "finally" enough to overcome the
fact that it does an extra mask).
Code in the appendix.
Cheers,
Max
===
{-# LANGUAGE Rank2Types #-}
import Control.Exception
import Criterion.Main
{-# NOINLINE bracket_no_finally #-}
bracket_no_finally :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket_no_finally before after thing =
mask $ \restore -> do
a <- before
r <- restore (thing a) `onException` after a
_ <- after a
return r
{-# NOINLINE bracket_finally #-}
bracket_finally :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket_finally before after thing =
mask $ \restore -> do
a <- before
r <- restore (thing a) `finally` after a
return r
{-# NOINLINE test_bracket #-}
test_bracket :: (forall a b c. IO a -> (a -> IO b) -> (a -> IO c) ->
IO c) -> IO ()
test_bracket bracket = bracket (return ()) (\() -> return ()) (\() -> return ())
main = defaultMain [
bench "finally" $ test_bracket bracket_finally
, bench "no finally" $ test_bracket bracket_no_finally
]
More information about the Haskell-Cafe
mailing list