-The type variable e used here represents the element type, while ce is the type
-of the container itself. Within this framework, we might want to define
-instances of this class for lists or characteristic functions (both of which
-can be used to represent collections of any equality type), bit sets (which can
-be used to represent collections of characters), or hash tables (which can be
-used to represent any collection whose elements have a hash function). Omitting
-standard implementation details, this would lead to the following declarations:
-<programlisting>
- instance Eq e => Collects e [e] where ...
- instance Eq e => Collects e (e -> Bool) where ...
- instance Collects Char BitSet where ...
- instance (Hashable e, Collects a ce)
- => Collects e (Array Int ce) where ...
-</programlisting>
-All this looks quite promising; we have a class and a range of interesting
-implementations. Unfortunately, there are some serious problems with the class
-declaration. First, the empty function has an ambiguous type:
-<programlisting>
- empty :: Collects e ce => ce
-</programlisting>
-By "ambiguous" we mean that there is a type variable e that appears on the left
-of the <literal>=></literal> symbol, but not on the right. The problem with
-this is that, according to the theoretical foundations of Haskell overloading,
-we cannot guarantee a well-defined semantics for any term with an ambiguous
-type.
-</para>
-<para>
-We can sidestep this specific problem by removing the empty member from the
-class declaration. However, although the remaining members, insert and member,
-do not have ambiguous types, we still run into problems when we try to use
-them. For example, consider the following two functions:
-<programlisting>
- f x y = insert x . insert y
- g = f True 'a'
-</programlisting>
-for which GHC infers the following types:
-<programlisting>
- f :: (Collects a c, Collects b c) => a -> b -> c -> c
- g :: (Collects Bool c, Collects Char c) => c -> c
-</programlisting>
-Notice that the type for f allows the two parameters x and y to be assigned
-different types, even though it attempts to insert each of the two values, one
-after the other, into the same collection. If we're trying to model collections
-that contain only one type of value, then this is clearly an inaccurate
-type. Worse still, the definition for g is accepted, without causing a type
-error. As a result, the error in this code will not be flagged at the point
-where it appears. Instead, it will show up only when we try to use g, which
-might even be in a different module.
-</para>
-
-<sect4><title>An attempt to use constructor classes</title>
-
-<para>
-Faced with the problems described above, some Haskell programmers might be
-tempted to use something like the following version of the class declaration:
-<programlisting>
- class Collects e c where
- empty :: c e
- insert :: e -> c e -> c e
- member :: e -> c e -> Bool
-</programlisting>
-The key difference here is that we abstract over the type constructor c that is
-used to form the collection type c e, and not over that collection type itself,
-represented by ce in the original class declaration. This avoids the immediate
-problems that we mentioned above: empty has type <literal>Collects e c => c
-e</literal>, which is not ambiguous.
-</para>
-<para>
-The function f from the previous section has a more accurate type:
-<programlisting>
- f :: (Collects e c) => e -> e -> c e -> c e
-</programlisting>
-The function g from the previous section is now rejected with a type error as
-we would hope because the type of f does not allow the two arguments to have
-different types.
-This, then, is an example of a multiple parameter class that does actually work
-quite well in practice, without ambiguity problems.
-There is, however, a catch. This version of the Collects class is nowhere near
-as general as the original class seemed to be: only one of the four instances
-for <literal>Collects</literal>
-given above can be used with this version of Collects because only one of
-them---the instance for lists---has a collection type that can be written in
-the form c e, for some type constructor c, and element type e.
-</para>
-</sect4>
-
-<sect4><title>Adding functional dependencies</title>