IO Monad Class Hierarchy: io-classes package
This package provides a monad class hierarchy which is an interface for both the io-sim and IO monads. It was developed with the following constraints in mind:
- be a drop-in replacement for IOmonad;
- IOinstances do not alter its original semantics, providing a shallow bindings to async, base, stm, and exceptions packages as well as timer API;
- provide zero-cost abstractions.
We provide also non-standard extensions of this API in sublibraries:
- io-classes:strict-stm
    strict TVar's, and other mutableSTMvariables, with support of the nothunks library;
- io-classes:strict-mvar:
    strict MVars
- io-classes:si-timers: timers api: - 32-bit safe API using DiffTimemeasured in seconds (rather than time in microseconds represented asIntas inbase)
- cancellable timeouts.
 
- 32-bit safe API using 
- io-classes:mtl: MTL instances.
io-classes:strict-stm and nothunks were successfully used in a large code base to eliminate space leaks and keep that property over long development cycles.
Documentation
Hackage doesn't yet support public sublibraries, thus Haddocks are published here.
Support material
Exception Class Hierarchy
This package provides an alternative class hierarchy giving access to
exceptions API. The [exception] package class hierarchy is also
supported by io-sim, so you
can also use either one.
The MonadThrow defined in this package allows working with exceptions
without having explicit access to catch or mask. It only provides
access to throwIO, bracket, bracket_, and finally. MonadCatch
class provides API which allows working with exceptions, e.g. catch or
bracketOnError, and MonadMask gives access to low-level mask and
friends. This division makes code review process somewhat easier. Using
only MonadThrow constraint, the reviewer can be sure that no low-level
exception API is used, which usually requires more care. Still
MonadThrow is general enough to do resource handling right.
Time and Timer APIs
The time and timer APIs of this package follows closely the API exposed
by base and
time packages. We separately
packaged a more convenient API in
si-timers
(ref SI),
which provides a monoidal action of DiffTime on monotonic time as well
as exposes 32-bit safe timer API (on 32-bit systems time in microseconds
represented as an Int can only hold timeouts of ~35 minutes).
si-timers sublibrary provides cancellable timers API, see registerDelayCancellable.
Control.Monad.Class.MonadTimer.NonStandard.MonadTimeout provides a
low-level timeout abstraction. On systems that support a native timer
manager, it's used to implement its API, which is very efficient even
for low-latency timeouts. On other platforms (e.g. Windows), it's
good enough for subsecond timeouts but it's not good enough for
fine-grained timeouts (e.g. sub milliseconds) as it relays on the GHC
thread scheduler. We support MonadTimeout on Linux, MacOS,
Windows, and IOSim (and unofficially on GHCJS).
MonadDelay and MonadTimer classes provide a well-established
interface to delays & timers.
Software Transactional Memory API
We provide two interfaces to stm API: lazy, included in
io-classes;
and strict one provided by
io-classes:strict-stm.
Threads API
We draw a line between base API and async API. The former is
provided by
MonadFork
the latter by
MonadAsync
Both are shallow abstractions around APIs exposed by the base and
async packages.
MVar API
We also provide lazy and strict MVars:
- lazy MVar API
- strict MVar API is provided in the io-classes:strict-mvar sublibrary.
Some other APIs
- MonadEventlog: provides an API to the Debug.Trace event log interface.
- MonadST:
    provides a way to lift ST-computations.
- MonadSay: dummy debugging interface
Monad Transformers
We provide support for monad transformers, see io-classes:mtl sublibrary. Although at this stage it might have its limitations and so there might be some rough edges. PRs are welcomed, contributing.
Differences from base, async, or exceptions packages
Major differences
- getMonotonicTimereturns- Time(a newtype wrapper around- DiffTime)
- Deadlockexceptions are not thrown to the main thread (see ref), so they cannot be caught. This was a design decision, which allows to catch all deadlocks which otherwise could be captured by a- catch.
Minor differences
Some of the types have more general kind signatures, e.g.
type Async :: (Type -> Type) -> Type -> Type
The first type of kind Type -> Type describes the monad which could be
instantiated to IO, IOSim or some other monad stacks built with
monad transformers. The same applies to many other types, e.g. TVar,
TMVar.
The following types although similar to the originals are not the same
as the ones that come from base, async, or exceptions packages:
- Handler(origin:- base)
- MaskingState(origin:- base)
- Concurrently(origin:- async)
- ExceptionInLinkedThread(origin:- async):- io-classes version does not store- Async
- ExitCase(origin:- exceptions)
Debuging & Insepction
We provide quite extended debugging & inspection API. This proved to be extremely helpful when analysing complex deadlocks or livelocks or writing complex quickcheck properties of a highly concurrent system. Some of this is only possible because we can control the execution environment of io-sim.
- labelThreadas part of- MonadThread(IO, io-sim, which is also part of- GHCAPI, ref labelThread);
- MonadLabelledSTMwhich allows to label of various- STMmutable variables, e.g.- TVar,- MVar, etc. (io-sim, not provided by- GHC);
- MonadInspectSTMwhich allows inspecting values of- STMmutable variables when they are committed. (io-sim, not provided by- GHC).
IO Simulator Monad: io-sim package
A pure simulator monad built on top of the lazy ST monad which
supports:
- optional dynamic race discovery and schedule exploration (see IOSimPOR)
- synchronous and asynchronous exceptions; including: throwing, catching and masking synchronous and asynchronous exceptions;
- concurrency (using simulated threads), with interfaces shaped by the
    baseandasynclibraries;
- software transactional memory (STM);
- simulated time;
- timeouts;
- dynamically typed traces and event log tracing;
- lifting any STcomputations;
- inspection of STMmutable data structures;
- deadlock detection;
- MonadFixinstances for both IOSim and its corresponding- STMmonad.
io-sim together with
io-classes
is a drop-in replacement for the IO monad (with some ramifications).
It was designed to write easily testable Haskell code (including
simulating socket programming or disk IO). Using
io-classes
and
si-timers
libraries one can write code that can run in both: the real IO and the
IOSim
monad provided by this package. One of the design goals was to keep the
API as close as possible to base, exceptions, async, and stm
packages.
io-sim package also provides two interpreters, a standard one and IOSimPOR which supports dynamic discovery of race conditions and schedule exploration with partial order reduction.
io-sim provides API to
explore traces produced by a simulation. It can contain arbitrary
Haskell terms, a feature that is very useful to build property-based
tests using QuickCheck.
The package contains thorough tests, including tests of STM against
the original specification (as described in
Composable Memory Transactions
and its GHC implementation. This can be seen in both ways: as a check
that our implementation matches the specification and the GHC
implementation, but also the other way around: that GHCs STM
implementation meets the specification.
Supporting material
Packages
io-classes-1.8.0.1
- Control- Concurrent
- Monad- Class- Control.Monad.Class.MonadAsync
- Control.Monad.Class.MonadEventlog
- Control.Monad.Class.MonadFork
- Control.Monad.Class.MonadST
- Control.Monad.Class.MonadSTM
- Control.Monad.Class.MonadSay
- Control.Monad.Class.MonadTest
- Control.Monad.Class.MonadThrow
- Control.Monad.Class.MonadTime
- Control.Monad.Class.MonadTimer
- Control.Monad.Class.MonadUnique
 
 
- Class
 
- Concurrent
io-classes:mtl-1.8.0.1
- Control- Monad- Class- MonadEventlog
- MonadST
- MonadSTM
- MonadSay
- MonadThrow
- MonadTime
- MonadTimer
- MonadUnique
- Control.Monad.Class.Trans
 
 
- Class
 
- Monad
io-classes:si-timers-1.8.0.1
- Control- Monad- Class- MonadTime
- MonadTimer
 
 
- Class
 
- Monad
io-classes:strict-mvar-1.8.0.1
- Control- Concurrent- Class
 
 
- Concurrent
io-classes:strict-stm-1.8.0.1
- Control- Concurrent- Class
 
- Class
 
- Concurrent
io-classes:testlib-1.8.0.1
- Test- Control- Concurrent- Class- MonadMVar
 
 
- Class
 
- Concurrent
 
- Control
io-sim-1.8.0.1
- Control- Monad
 
- Data- List