Home > OS >  When is `after` called?
When is `after` called?

Time:09-07

There is a good known function - bracket:

bracket
        :: IO a         -- ^ computation to run first (\"acquire resource\")
        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
        -> (a -> IO c)  -- ^ computation to run in-between
        -> IO c         -- returns the value from the in-between computation
bracket before after thing =
  mask $ \restore -> do
    a <- before
    r <- restore (thing a) `onException` after a
    _ <- after a
    return r

I see two calls of after: once on an exception, the second time - _ <- after a - in all cases (with exception/without exception). I call this:

bracket (pure 1) (\a -> print a >> pure a) (\a -> head [])

And print happens only once. Then why, with 2 afters? How does it work at all?

Could somebody explain in details how this snippet:

r <- restore (thing a) `onException` after a
_ <- after a

work exactly?

ps. I tried bang (!..) patterns, and nothing changed, it seems it is not about lazy evaluation...

EDIT: experiment with own (more specific logic) implementation:

mybracket
        :: IO a                    -- ^computation to run first (\"acquire resource\")
        -> (Maybe c -> a -> IO c)  -- ^computation to run last (\"release resource\")
        -> (a -> IO c)             -- ^computation to run in-between
        -> IO c                    -- returns the value from the in-between computation
mybracket before after thing =
  mask $ \restore -> do
    a <- before
    r <- restore (thing a) `onException` after Nothing a
    r1 <- after (Just r) a
    return r1

Can I be sure that mybracket will call after just once - for exception in thing and when no any exceptions, in both cases?

CodePudding user response:

onException re-throws the exception. So in this snippet,

                                 -- if
                                 -- `action` returns normally | `action` throws an exception
                                 -- then
r <- action `onException` after  -- this `after` doesn't run  | this `after` runs 
_ <- after                       -- that `after` runs         | that `after` doesn't run
...

... either action succeeds, then the `onException` after is ignored and only _ <- after runs. Or action throws an exception, then after `onException` after re-throws the exception after running after, and _ <- after doesn't run.

  • Related