- Each MonadConc has an associated MonadSTM, transactions of which
it can run atomically.
- The MonadSTM for IO is STM.
- Conc and ConcIO do not yet have a MonadSTM.
This adds a new `MonadConc` primitive, `_concNoTest`, which is (for
all non-test implementations) the identity function. For test
implementations, it is understood as "this action is completely safe
under all schedules, so just execute it all at once and don't consider
any internal interleavings." It is not required to be deterministic,
merely to never fail.
Actions annotated with `_concNoTest` will show up as one step in the
trace, and new `Failure` and `ThreadAction` values have been added.
- Tweak order in which schedules are explored to look at simple,
but not too simple, cases first.
- Port simplicity logic from shrinking to dupe elimination.
Shrinking attempts to find a "maximally simple" trace which
exhibits the same bug as the original. Typically, this means that
the results are equal. Shrinking is implemented in terms of
recursively trying to find the simplest variant of the original
trace, where simplest in particular means:
1. A trace with fewer pre-emptions is simpler.
2. A trace with fewer non-pre-emptive context switches is simpler.
3. A trace lexicographically smaller is simpler.
These three criteria are applied in that order in order to determine
which the simplest trace out of a collection is.
For test output, there is a final set of simplification done at the end.
Shrinking attempts to reduce individual traces to their simplest variant,
which can result in multiple test failures having the same shrunk trace.
Thus, the test runner then filters out duplicate failures by only keeping
the simplest trace for a given result.