Lifting up from I/O
In real-world applications, it's quite usual for much of the code base to live in monads or monad stacks. In such situations, concurrency operations from Control.Concurrent
become challenging, because they all are monomorphic in IO
. Sometimes this isn't much of a problem, because we can use liftIO
from the MonadIO
class to lift arbitrary IO actions.
But MonadIO
leaves two important cases uncovered. The first one is about other base monads besides IO
, such as STM
. Though more limited in its use cases, it's sometimes desired to have a monad stack on top of STM
. The other case is about exception handling, for which MonadIO
is quite insufficient; all of Control.Exception
is monomorphic in IO
, meaning a lot of plumbing if they are used within a monad stack.
In this chapter, we'll look at some solutions to both cases. Another thing that's often desired, and which we'll cover first, is top-level mutable references. In some languages these are called globals
, and though they're...