Kevin Meredith
Kevin Meredith

Reputation: 41919

Understanding `bracket` Function

Looking at the bracket function from Parallel and Concurrent Programming in Haskell:

bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket before after during = do
  a <- before
  c <- during a `onException` after a
  after a
  return c

In the event of an exception, why does the after function only get called once? In other words, I'm confused at the apparent execution of after a twice in the event of an exception.

But, the code shows that after a only gets called, as I understand, once:

λ: >data MyException = MyException deriving Show
λ: >instance Exception MyException

λ: >let e = return MyException :: IO MyException

λ: >bracket e (const $ putStrLn "clean up!") return
clean up!
MyException

Upvotes: 4

Views: 430

Answers (1)

Jon Purdy
Jon Purdy

Reputation: 55049

From the docs for bracket:

When you want to acquire a resource, do some work with it, and then release the resource, it is a good idea to use bracket, because bracket will install the necessary exception handler to release the resource in the event that an exception is raised during the computation. If an exception is raised, then bracket will re-raise the exception (after performing the release).

And onException:

Like finally, but only performs the final action if there was an exception raised by the computation.

So if there is an exception thrown from during a, the first call to after a is executed, then the exception is rethrown, skipping the second after a; if there is no exception, only the second is executed.

Note that in your sample code, you’re returning an exception, not throwing it—to throw, you need to use throw or preferably throwIO :: Exception e => e -> IO a.

Upvotes: 6

Related Questions