- All non-IO haskell code is automatically safe by construction. This is the one factor that makes asynchronous exceptions feasible.
- When working with resources: bracket and so have built in support for asynchronous-exceptions.
- When working with MVar: use modifyMVar and so.
A couple of thecniques can simplify matters:
-
Large chunks of heavily stateful code can be wrapped in a mask, which drops into polling mode for asynchronous exceptions. This is much easier to work with. The problem then boils down to finding the interruptible operations and ensuring that exceptions raised by those will not cause problems. The GHC I/O library uses this technique: every Handle operation runs entirely inside mask.
-
Using software transactional memory (STM) instead of MVars or other state representations can sweep away all the complexity in one go. STM allows us to combine multiple operations in a single atomic unit, which means we don’t have to worry about restoring state if an exception strikes in the middle. We will describe STM in Chapter 10.
-
Many exceptional conditions map naturally onto asynchronous exceptions. For example, stack overflow and user interrupt (e.g., Ctrl+C at the console) are mapped to asynchronous exceptions in Haskell. Hence, Ctrl+C not only aborts the program but also does so cleanly, running all the exception handlers. Haskell programmers don’t have to do anything to enable this behavior.
-
Computation can always be interrupted, even if it is third-party library code. (There is an exception to this, namely calls to foreign functions, which we shall discuss in Threads and Foreign Out-Calls).
-
Threads never just die in Haskell. It is guaranteed that a thread always gets a chance to clean up and run its exception handlers.