Some context, for those with no Haskell experience: a ‘typeclass’ (no relation to OOP ‘classes’) is a way of abstracting over a function which can be implemented for numerous different types, very much like ‘interfaces’ in Java or C#. For instance, the ‘Eq’ typeclass provides the equality operators:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
Which can then be implemented for various types, allowing any of those types to be compared for equality using (==) and (/=). You can also write functions which are polymorphic over all types implementing a typeclass, e.g.:
allThreeUnequal :: Eq a => a -> a -> a
allThreeUnequal a b c = (a /= b) && (b /= c) && (a /= c)
-- (/=) here is provided by the ‘Eq a’ constraint
-- in the signature
I tend to think of typeclasses in Haskell — and especially the ones listed in the Typeclassopedia — almost as allowing the formalisation of design patterns and common conventions. For instance, many languages have multiple ‘map’ functions: one mapping a function over a list, one over a promise, and so on. Haskell, by contrast, unifies those in single ‘Functor’ typeclass, with one polymorphic function ‘fmap’. (The (in)famous ‘Monad’ typeclass is also very similar in its aims: compare C#, where precisely the same behaviour gets encoded in a mere convention declaring that a certain function should be named ‘SelectMany’.) The advantage of all this is that you can write very highly generic (hence reusable) code while still retaining typesafety. In fact, the effect tends to be remeniscient of duck typing, just more typesafe.