Resource management becomes unsafe when acquisition, use, and disposal are scattered across application code. The bracket pattern centralizes that lifetime: acquire one resource, run an action, and dispose of the resource afterward. section 10.0 section 10.3.2
The bracket function accepts initialization, release, and utilization functions. Keep one resource per bracket. For several resources, nest brackets so each acquired resource has an individual disposal scope; if an action fails, cleanup runs before the exception is rethrown. section 10.3.2 section 10.4
Sentry logging service
A main function can bracket Sentry initialization with its disposal and application action: initialize the service, run doSomething with it, then deinitialize it. Applying one bracket per resource avoids partially initialized bundles and long-lived resources left behind after failures. section 10.3.2
bracket :: IO resource -- acquire the resource -> (resource -> IO ()) -- release the resource -> (resource -> IO result) -- utilize the resource -> IO result -- return the result
Use the type signature to see the bracket contract: acquire a resource, release it, use it, and return the action result. section 10.3.2
main = bracket initResourceA deinitResourceA (\resourceA -> bracket initResourceB deinitResourceB (\resourceB -> bracket initResourceC deinitResourceC (\resourceC -> utilizeMyResources (resourceA, resourceB, resourceC) )))
Nested brackets make resource lifetimes explicit and ensure outer resources remain available for cleanup when inner actions fail. section 10.3.2
