How do you write (==) for many types when each compares differently? A typeclass declares an interface (class Eq a where (==) : a → a → Bool); each type provides an instance; and the compiler, at each call, passes the right instance as a hidden dictionary of operations. This is Wadler & Blott's answer to Strachey's ad-hoc polymorphism — different behavior per type, but resolved by the type checker, not by runtime tags. Dictionary-passing is the whole trick: a typeclass constraint Eq a => compiles to an extra argument, the dictionary.
An Eq instance is a dictionary carrying (==). The demo dispatches through the dictionary on two inputs: live demo
“Overloading is a runtime lookup on the value's tag.” — a typeclass resolves the overload at compile time from the type, then passes the chosen operations along explicitly. No runtime tag, no guessing — the dictionary is decided before the program runs. cited
The constraint Eq a => is a function argument in disguise: the dictionary of operations for a. Overloading becomes ordinary passing — ad hoc made principled. Wadler-Blott 1989
On the canonical compiler, dispatching (==) through the Eq dictionary gives 5==5 → 1 and 5==6 → 0: