5 ms·
It's more that classes just don't behave the same as `class` in an OOP sense. You can create a subtype hierarchy using typeclasses—Functor->Application->Monad->
by tel 13y ago
It's more that classes just don't behave the same as `class` in an OOP sense. You can create a subtype hierarchy using typeclasses—Functor->Application->Monad->MonadPlus/Applicative is a great example and the `lens` hierarchy is an even more sophisticated one.
But these are subtype hierarchies, not subclass hierarchies. Furthermore, classes don't necessarily provide you with the full convenience of an object, though they can come close. Finally, people aren't used to working in codata and Haskell doesn't make it easy, so you have trouble there, too.
- Chattered 13y agoYou can't create subtype hierarchies in Haskell. Haskell doesn't have any subtyping: every value has exactly one type. This is why you cannot use the OOP solution for the game, which requires lists whose elements have a common supertype. Even with existential types (as the author mentions), you still do not have any subtyping. Typeclasses are collections of types. All types in the applicative class are also in the functor class, but none of these types are subtypes of any others.
- seanmcdirmid 13y agoThere's always O'haskell. I believe normal Haskell does support structural subtyping, even if not nominal.
- Sssnake 13y ago>There's always O'haskell. No, there isn't. Last update was in 2001. It was never really alive, but it is very dead now.
- seanmcdirmid 13y agoRight, but it still demonstrates how nominal subtyping could be added to Haskell.
- tel 13y agoExcept there are quantified types, so `forall a. Functor a => a` is the type of "all types instantiating Functor" and `forall a. Applicative a => a` is a subtype. These are commonly used due to the implicit forall quantification. Edit: I'm rusty here, but after re-reading the LSP I'd also say that existential types could exhibit subtyping as the set of statements provable about them is often exactly those provable about the universally quantified type.
- Chattered 13y agoNeither of the types you gave is inhabited, because the 'a' has kind * -> * . I think what you've said about subtyping is muddled. If a type A is a subtype of B, then values of type A should be values of type B. Now let's take an example from the number class hierarchy. Consider 1) forall a. Num a => a 2) forall a. Integral a => a According to what you have written, (2) should be a subtype of (1). That means that if I define n = 1 :: forall a. Integral a => a then I should be able to "upcast" with: n :: forall a. Num a => a However, this doesn't work, since the quantifier now ranges over types that were not in the range of the original quantifier. In the second type, I can instantiate the a to Float, while I cannot do so for the first type. The only formal account of universal quantifiers in type theory, of which I am aware, extends the term language by introducing a capital lambda that ranges over types. So the polymorphic identity function is actually the term Λa. λx:a. x which is a function that takes a type a followed by a value x:a and returns x. This makes good sense of the way number classes work in Haskell. When you write n :: Num a => a n = 1 the actual machine representation of n is going to vary with the type of a. EDIT: Another way of explaining the counterexample: any type in Applicative is also in Functor. But, on one informal interpretation of forall, the intersection of all applicatives is actually a proper superset of the intersection of all functors.