It is unfortunate that two completely different concepts both happen to use the word "class" in their name. A related example is "return". People coming from a background in, say, C++ or Java will naturally have preconceptions about what these words mean, and will almost inevitably start by trying to apply them in Haskell world where they don't work.
It is particularly unfortunate because, with the wisdom of hindsight, I think classes as used in C++ and Java have been responsible for many problems over the years. This is fundamentally because they take two very common, very useful ideas -- modular design (separation of interface and implementation) and compound data types (struct/record/variant/etc.) -- and try to use a single tool to implement both at the same time.
Unfortunately, that creates all kinds of presumptions about how you write your functions, where the emphasis is always on one object being paramount or one data type controlling everything. For practical programming tasks, it may be more useful to model a situation using a set of related types to hold the data and a set of algorithms defined in terms of one or more of those data types (or more generally collections of one or more such types) to manipulate that data.
It's probably not an exaggeration to say that almost all of the most common modelling problems with C++/Java style OOP -- the "diamond pattern" with multiple inheritance, for example -- are due at least in part to this unwarranted emphasis on this/self/whatever you want to call it. Much of the rest is due to over-use of inheritance, which again has an underlying subclass-or-subtype ambiguity in what it represents -- and which again is perhaps emphasized by the whole one-object-to-rule-the-world philosophy even when what OOP would call containment or aggregation is a clearer way to model the situation.
Languages such as Haskell have never had this history of conflating modular design with structuring data, nor the resulting false friend of emphasizing one object/value/whatever in any given modelling context. IME, this is the big conceptual leap that is sometimes hard for those with a strongly everything-is-an-object background to make, though it's perhaps a little easier these days for anyone who has used C++ templates or Java generics. Once you make the jump, type classes and algebraic data types make a lot more sense.
Comments
It is unfortunate that two completely different concepts both happen to use the word "class" in their name. A related example is "return". People coming from a background in, say, C++ or Java will naturally have preconceptions about what these words mean, and will almost inevitably start by trying to apply them in Haskell world where they don't work.
It is particularly unfortunate because, with the wisdom of hindsight, I think classes as used in C++ and Java have been responsible for many problems over the years. This is fundamentally because they take two very common, very useful ideas -- modular design (separation of interface and implementation) and compound data types (struct/record/variant/etc.) -- and try to use a single tool to implement both at the same time.
Unfortunately, that creates all kinds of presumptions about how you write your functions, where the emphasis is always on one object being paramount or one data type controlling everything. For practical programming tasks, it may be more useful to model a situation using a set of related types to hold the data and a set of algorithms defined in terms of one or more of those data types (or more generally collections of one or more such types) to manipulate that data.
It's probably not an exaggeration to say that almost all of the most common modelling problems with C++/Java style OOP -- the "diamond pattern" with multiple inheritance, for example -- are due at least in part to this unwarranted emphasis on this/self/whatever you want to call it. Much of the rest is due to over-use of inheritance, which again has an underlying subclass-or-subtype ambiguity in what it represents -- and which again is perhaps emphasized by the whole one-object-to-rule-the-world philosophy even when what OOP would call containment or aggregation is a clearer way to model the situation.
Languages such as Haskell have never had this history of conflating modular design with structuring data, nor the resulting false friend of emphasizing one object/value/whatever in any given modelling context. IME, this is the big conceptual leap that is sometimes hard for those with a strongly everything-is-an-object background to make, though it's perhaps a little easier these days for anyone who has used C++ templates or Java generics. Once you make the jump, type classes and algebraic data types make a lot more sense.