
Shelby Moore wrote:
...A "type class" is a polymorphic (relative to data type) interface, and the polymorphism is strictly parameterized for the client/consumer of the interface, i.e. the data type is known to the function that inputs the interface AT COMPILE TIME.
...A problem with virtual (runtime pointer) inheritance is that it hides the subclass from the compiler.
I emphasize that in Haskell, the consuming function knows the interface at compile time (or it can allow the compiler to infer it, if no type class restriction is specified).
...if one means by "style" the conflation of the interface with the data and/or use of virtual (runtime) base class inheritance and the style of that induces, then it is an architectural mistake...
One explanation of how "extends" (base class) does impact composability: http://www.haskell.org/pipermail/haskell-cafe/2009-October/068337.html Instead encapsulate ("inherit") data type orthogonal to "type class" (interface) in Haskell: http://www.haskell.org/pipermail/haskell-cafe/2009-October/068328.html
The point of that whole rant is that extending data-bearing classes isn't necessarily a good idea, so before trying to find a way to do it with haskell, it may be better to just encapsulate another data type, which is trivial:
data InnerThing = A | B | C
data OuterThing = Outer { innerThing :: InnerThing, otherField :: Int }
Additionally note: Shelby Moore wrote:
In Haskel, subtyping is done with Module...
data is analogous to a public class members. Use Module to make some implementation private: http://www.cs.auckland.ac.nz/references/haskell/haskell-intro-html/modules.h... Thus use type classes (interfaces) when consuming the public Module interfaces in functions (i.e. only consume the exported Module interfaces in the sense they implement a type class, never directly consume the Module name space). I realize some examples would make the above easier to visualize.