The paper which introduced type classes was "How to make ad-hoc polymorphism less ad-hoc" by Wadler and Blott in 1988. In the paper, they mention that type classes were discovered during the standardization work on Haskell, however the wording doesn't make it clear who discovered them. (One would assume it was the authors, but that isn't said explicitly.)
One practical example I like comes from the world of programming languages: the set of types in an OO system is bounded and discrete but not enumerable, and partially ordered but not totally ordered.
The partial ordering in question is the subtyping relation <:. The upper bound would then be the top type (which C# calls object and Scala calls Any), and ...
Since both are in OCaml, We can explore the difference between generative and applicative functors easily:
module type S = sig type t end
module M = struct type t = int end
(* An Applicative functor. *)
module F (M : S) = struct
type t = Foo of M.t list
module F1 = F(M)
module F2 = F(M)
(* M1 = M2 => F(M1).t ≡ F(M2).t
let x : ...
It's because the operations are independent, so tying them together with a subclass relationship doesn't actually buy you anything. Say you wanted to create a custom type that implemented Bounded, perhaps Doubles constrained between a max and min, but you had no need for any of the Enum operations. If Bounded were a subclass, you would have to implement ...
Usually in this sort of situation, you would just create a simple data type or perhaps a record to aggregate the different fields:
data Displayable = Displayable Picture (Float,Float) (Float,Float) Float
Type classes are for when you need polymorphic dispatch to many implementations of the same function. That's certainly not the case for scale and ...
It's usually a good idea avoid type classes unless it provides a specific benefit that cannot be gained by any other means. This article provides a somewhat extreme view on this, so take it with a grain of salt, but it can help you understand why type classes can be troublesome.
The main issue type classes operate on the type level, which means that trying ...
There are different mechanisms of polymorphism. Except for parametric polymorphism, these dispatch control flow depending on the type of function arguments. In other words: they are some kind of function overloading. The arguments can either be considered for their static type or for their dynamic type. If we dispatch a call on a static type, we call this ad-...