I don't think I understand type classes. I'd read somewhere that thinking of them as interfaces (from OO) that a type implements is wrong and misleading. The problem is, I'm having a problem seeing them as something different and how that is wrong.For example, if I have a type class (in Haskell syntax)class Functor f where  fmap :: (a -> b) -> f a -> f bHow is that different than the interface [1] (in Java syntax)interface Functor<A> {  <B> Functor<B> fmap(Function<B, A> fn)}interface Function<Return, Argument> {  Return apply(Argument arg);}One possible difference I can think of is that the type class implementation used at a certain invocation is not specified but rather determined from the environment - say, examining available modules for an implementation for this type. That seems to be an implementation artifact that could be addressed in an OO language; like the compiler (or runtime) could scan for a wrapper/extender/monkey-patcher that exposes the necessary interface on the type.What am I missing?[1] Note the f a argument has been removed from fmap since given it's an OO language, you'd be calling this method on an object. This interface assumes the f a argument has been fixed.
Type classes vs object interfaces?
pl.programming languages;type theory;type systems
In their basic form, type classes are somewhat similar to object interfaces. However, in many respects, they are much more general.Dispatch is on types, not values. No value is required to perform it. For example, it is possible to do dispatch on the result type of function, as with Haskell's Read class:class Read a where  readsPrec :: Int -> String -> [(a, String)]  ...Such dispatch is clearly impossible in conventional OO.Type classes naturally extend to multiple dispatch, simply by providing multiple parameters:class Mul a b c where  (*) :: a -> b -> cinstance Mul Int Int Int where ...instance Mul Int Vec Vec where ...instance Mul Vec Vec Int where ...Instance definitions are independent from both class and type definitions, which makes them more modular. A type T from module A can be retrofitted to a class C from module M2 without modifying the definition of either, simply by providing an instance in module M3. In OO, this requires more esoteric (and less OO-ish) language features like extension methods.Type classes are based on parametric polymorphism, not subtyping. That enables more accurate typing. Consider e.g.pick :: Enum a => a -> a -> apick x y = if fromEnum x == 0 then y else xvs.pick(x : Enum, y : Enum) : Enum = if x.fromEnum() == 0 then y else xIn the former case, applying pick '\0' 'x' has type Char, whereas in the latter case, all you'd know about the result would be that it's an Enum. (This is also the reason why most OO languages these days integrate parametric polymorphism.)Closely related is the issue of binary methods. They are completely natural with type classes:class Ord a where  (<) :: a -> a -> Bool  ...min :: Ord a => a -> a -> amin x y = if x < y then x else yWith subtyping alone, the Ord interface is impossible to express. You need a more complicated, recursive form or parametric polymorphism called F-bounded quantification to do it accurately. Compare Java's Comparable and its use:interface Comparable<T> {  int compareTo(T y);};<T extends Comparable<T>> T min(T x, T y) {  if (x.compareTo(y) < 0)    return x;  else    return y;}On the other hand, subtyping-based interfaces naturally allow the formation of heterogeneous collections, e.g. a list of type List<C> can contain members that have various subtypes of C (although it is not possible to recover their exact type, except by using downcasts). To do the same based on type classes, you need existential types as an additional feature.