Data types

The Resource transformer. This transformer keeps track of all registered
actions, and calls them upon exit (via runResourceT). Actions may be
registered via register, or resources may be allocated atomically via
with or withIO. The with functions correspond closely to bracket.

Releasing may be performed before exit via the release function. This is a
highly recommended optimization, as it will ensure that scarce resources are
freed early. Note that calling release will deregister the action, so that
a release action will only ever be called once.

Unwrap

Unwrap a ResourceT transformer, and call all registered release actions.

Note that there is some reference counting involved due to resourceForkIO.
If multiple threads are sharing the same collection of resources, only the
last call to runResourceT will deallocate the resources.

Special actions

Introduce a reference-counting scheme to allow a resource context to be
shared by multiple threads. Once the last thread exits, all remaining
resources will be released.

Note that abuse of this function will greatly delay the deallocation of
registered resources. This function should be used with care. A general
guideline:

If you are allocating a resource that should be shared by multiple threads,
and will be held for a long time, you should allocate it at the beginning of
a new ResourceT block and then call resourceForkIO from there.

Monad transformation

Transform the monad a ResourceT lives in. This is most often used to
strip or add new transformers to a stack, e.g. to run a ReaderT. Note that
the original and new monad must both have the same Base monad.

Low-level

A base monad which provides mutable references and some exception-safe way
of interacting with them. For monads which cannot handle exceptions (e.g.,
ST), exceptions may be ignored. However, in such cases, scarce resources
should not be allocated in those monads, as exceptions may cause the
cleanup functions to not run.