### Updated: 26 August 2011

2. Background: type classes were originally introduced to reconcile overloading with type inference (or type reconstruction) in implicitly-typed languages of the ML family. Hindley-Damas-Milner's type-inference algorithm W can infer the most general type of a function. For example, in the case of the identity function, id x = x, algorithm W infers the parametrically polymorphic type ∀a.a→a. A parametrically polymorphic function captures families of monomorphic functions with uniform behaviour. The uniformity is illustrated by the internal representation of the function where the type of the data on which it acts is a parameter: id a x = x. The application id Int is the identity function on integers (and x must be an integer), id Float the identity function on floats, etc. The body of each monomorphic identity is identical save for the type annotation.

In contrast, overloaded functions don't have the same behaviour. This makes type inference problematic. A hoary example is arithmetical multiplication. The values and algorithms involved in integer and floating-point multiplication are different. We can't write a single function mult to do the job. We must write different overloaded versions, e.g.:

```  mult :: Int → Int → Int
mult x y = ...  -- integer multiplication

mult :: Float → Float → Float
mult x y = ...  -- floating-point multiplication
```

In this setting, overloading is resolved in terms of scope and type signatures of arguments, which means type signatures must be written explicitly. For example, without its type signature it is impossible to tell whether double below is a function on integers or floats:

``` double x = mult x x
```

However, providing type signatures leads to code bloating:

``` double :: Int → Int
double x = mult x x

double :: Float → Float
double x = mult x x
```

This is unsatisfactory. Despite the different behaviour, all the versions of mult and double are about the same idea, namely, about "multiplication" and "doubling" of numbers.

3. Type classes: overloaded functions are defined by making the varying types belong to the same type class. A type class defines a collection of types that is constructed in modular fashion. For example, type class Mult is the class of types for which mult has been implemented. The programmer must provide all inhabitants (witnesses) of the class.
``` class Mult a where
mult :: a → a → a

instance Mult Int where
mult = ...  -- integer multiplication

instance Mult Float where
mult = ...  -- floating-point multiplication
```

We can now define double x = mult x x. The type checker infers it has type ∀a. Mult a ⇒ a → a, meaning ∀a∈Mult. a → a. The idea is simple and clever: the overloaded function is now a parameter. Internally, double has type ∀a. MultD a → a → a where MultD is a dictionary type (record) with a mult member funcion. Overloading resolution for applications of double to actual values is based on the types of those values, which determine the particular instance of Mult and, consequently, the particular dictionary value of type MultD to be passed at run time.

4. However, overloading is about reusing names independently of whether a semantic relationship between types can be established by grouping them into the same type class. Even with type classes, we can't invoke overloaded functions within the same scope, e.g.:
```   push :: a → Stack a → Stack a
push :: Door → IO ()
```

The first function is a well-known function on stacks. The second displays on the screen the pushing of an emergency door in a fire simulation program. Both functions are meant to be used in the simulation. But stacks and doors don't belong in the same class. We must resort to resolving overloading manually in terms of scope, e.g., Stack.push, Door.push. In short, we must give up overloading and its automatic resolution.

We can't use within the same scope different abstractions sharing operator names. For instance, constructor type classes are employed in the definition of abstract data type interfaces:

``` class Queue q where
empty   :: q a
isEmpty :: q a → Bool
enqueue :: a → q a → q a
head    :: q a → a
tail    :: q a → q a

length :: Queue q ⇒ q a → Int
length q
| isEmpty q = 0
| otherwise = 1 + length (tail q)
```

We can't use head, tail, and length operators together with the list counterparts within the same scope unless we qualify their names by class/module. The conflict is between operators in different classes.

We can't define overloaded functions within the same type class:

```  class Vector m where
...
mult :: m a → m a → m a
mult :: a   → m a → m a
```

We can't overload (and override) functions in subclasses. This is why multiple subclassing is not a problem, in contrast with classes in object-oriented languages. For example:

``` class A a where ..
class A a ⇒ B a where ..
class A a ⇒ C a where ..
class (B a, C a) ⇒ D a where ..

A
/ \
B   C
\ /
D
```
There's no ‘diamon of death‘ conflict between B's, C's and D's function names cause they are all required to differ.

Summarising:

1. Cannot overload names within the same class.
2. Cannot overload names in different classes used within the same scope. Overloading takes place within the members of a class.
3. Cannot overload names in subclasses.
5. Related stuff: can't overload value constructors nor record members.

Value constructors play the role of type tags that help the type checker figure out the type of the value. For example, below is the type of disjoint sums:

``` data Sum a b = Inl a | Inr b
```

We cannot define overloaded value constructors:

```  MkSum :: a → Sum a b
MkSum :: b → Sum a b
```

What would the type of MkSum 3 be ?

We may provide type annotations to disambiguate:

```  (MkSum 3) :: Sum Int Bool
```

but this fails when both components have the same type (is 3 an Inl or an Inr?)

``` (MkSum 3) :: Sum Int Int
```

A way to disambiguate is to provide a type-tag proxy:

``` data INL = INL
data INR = INR

MkSum :: INL → a → Sum a b
MkSum :: INR → b → Sum a b

(MkSum INL 3) :: Sum Int Int
```

There is no confusion about which value is constructed. But this is resolving overloading manually, as with the original value constructors:

``` Inl = MkSum INL
Inr = MkSum INR
```
So better to have different value constructor names.