The reorderable package

The pair `(Int, Float)' is entirely distinct from the pair `(Float, Int)'
and trying to use one in place of the other will give a type error.
This is often, but not always, desired.

Module.

This module provides more flexible sum and product types that do not enforce
a single order on their elements. This does introduce some necessary
restrictions, for example only one instance of any type can appear in
any given collection of types. Additionally, all types that are to be
used in one of these flexible containers must be pre-defined as
reorderable:

That will, using Template Haskell, generate all the required instances to
make those types usable as reorderable types within unordered
containers. Following that, all the declarations below are valid:

Types Reordered1A and Reordered1B are in fact now identical. This does
introduce a third limitation of the library I have been unable to lift -
the use of ReorderableEnd as a sentinel in all reorderable containers.

It may be the case that Type1 and Type2 can be used together, as can
Type3 and Type4, but the two sets of types can not be used in a
container together. These are groups of types:

:<: Is read as "Is member of sum type".
* :>: Is read as "Is not member of sum type".
* :+: Is read as "Plus".
* :?: Is read as "Is member of product type".
* :~: Is read as "Is not member of product type".
* :*: Is read as "Product".
* :-: Is read as "Remove".

* Notes on the functions:

addSumX Adds the TYPE x to the given signature, and correctly
re-wraps the contained data to reflect this new structure. It does
not add any data in to the structure itself because only one item
may exist in the structure, and that item is already there.

setSumX Changes what data is currently stored in the sum. For a
given concrete sum type S, this can be called as:
`setSumX x (undefined :: S)'. An alternative version is simply:
`setSumType (undefined :: S) x', in which `X :<: S'. This is
equivalent to the original inj function from `Data Types 'a la
Carte', but has an explicit type proxy.

getSumX Returns the data of type `Just X' IF it is the data
currently being stored within the sum, otherwise it returns
Nothing. This is equivalent to the original prj function from
`Data Types 'a la Carte'.

addProductX Adds data of type X to an existing product type that
does not yet contain any data of that type.

setProductX Sets the data of type X in a product type that already
contains data of that type.

getProductX Gets the data of type X from a product type that
contains data of that type.

removeProductX Removes data of type X from a product type that
contains data of that type, and rewraps the resulting information to
remove X from the product's type. There is no removeSumX
function because the result is empty if the stored data is not of
the type being removed.

Generators.

In addition to being able to control for which types code is generated, you
can control what code is generated for them through reorderers. Note
that the default code listed above is ALWAYS generated, you can
currently only ADD to the generation code. The simplest way to explain
this is through an example:

The code above is exactly the code used to generate the sum type functions
documented above. The internal class names are used in place of the
type operator synonyms for simplicity. ??? is used as a placeholder
to be replaced by the unqualified type names from every instance of
reorderable in the code. The empty class ReorderableSum is a
unique name with a single type parameter, passed as the first symbol
to the reorderer. An instance of this class is generated for each
reorderable type, to track for which types this reorderer has already
been generated (using reify). The simple reason for this is that
placing the same type in two reorderableGroups will, without that
check, attempt to instantiate this code twice and thus give errors.

What can be done within generators is very constrained. For one thing, the
parameter a to ReorderableSum currently MUST have kind *, so any
reorderable types may not have type parameters themselves (unless a new
generator is written for exactly that type). Additionally, the
placeholder ??? in no way accounts for complex names - it is purely a
text-based replacement, so trying to create a reorderable ``Maybe Int''
type will result in the illegal:

addSumMaybe Int :: ...

Finally, this code is processed with "haskell-src-meta", and so any code
must be parsable with that code. One lifting of this restriction is
that reorderers may additionally contain type family declarations, which
are by default not supported by that library (despite having issued a
pull request many months ago).