Multiple-reader, single-writer locks. Used to protect shared resources which
may be concurrently read, but only sequentially written.

All functions are exception safe. Throwing asynchronous exceptions will not
compromise the internal state of an RWLock. This means it is perfectly safe
to kill a thread that is blocking on, for example, acquireRead.

A non-blocking withRead. First tries to acquire the lock. If that fails,
Nothing is returned. If it succeeds, the computation is performed. When the
computation terminates, whether normally or by raising an exception, the lock is
released and Just the result of the computation is returned.

A non-blocking withWrite. First tries to acquire the lock. If that fails,
Nothing is returned. If it succeeds, the computation is performed. When the
computation terminates, whether normally or by raising an exception, the lock is
released and Just the result of the computation is returned.