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 after
s? 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.