A brief zwischenzug -- Overloading and classes.
As I've said before, dealing with numerics complicates things. One of
the ways that it complicates things is that we want to have a diverse
set of types (Integer, Double, Complex, Ratio) that can all be
manipulated with similar sets of operations (+,-,*,==,<, etc.).
Now in Haskell, ordinarily, a function has to have a unique type at
least in the Hindley-Milner type algebra (which may involve universal
types), and a unique implementation (modulo guards).
So these two notions are at odds with one another, yet evidently
Haskell solves the problem.
What Haskell has done is to introduce the notion of a class -- this is
a collection of types that implement a coherent set of functions.
Each function has to be given a particular type (in the Haskell type
system), but the implementations are type specific.
E.g., the type of
(+) is always
a -> a -> a, i.e., it takes two items of the same type,
and produces a third object of that type, which works whenever a is a
Double, Integer, etc.
We'll get into the mechanics later, but here is an important example
from the Prelude:
:: a -> a -> Bool
x /= y
= not (x == y)
x == y
= not (x /= y)
This looks a bit odd, so let me explain.
First, we're declaring a class Eq, all of whose types have to implement
boolean predicates for equality and inequality.
Second, we're providing
*default* implementations (and we don't have to) of == and /=. What this
means is that instances can provide their own definitions of == and /=, but