8 ms·
You 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 soluti
by Chattered 13y ago
You 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.
- tel 13y agoAhh, hah. My mistake on the kinds. I changed it from an example on Num and Show because I don't much like how they're related.
- tel 13y agoI wouldn't expect (Integral a, Num b) => a -> b, but I do expect the opposite. That seems to be exactly the definition of LSP. And yeah, if you add System F type binders then you can do all of this explicitly, you just need to also manually pass around instance dictionaries. A morphism from one instance dictionary to another (which "forgets" "methods") provides your subtyping relation.
- Chattered 13y agoYou have (Integral a, Num b) => a -> b It's just the function fromIntegral. You don't have the opposite, if, by which, you mean (Num a, Integral b) => a -> b I was talking about giving the same expression multiple types. So you can have: n :: Num a => a n = 1 and then do n :: Integral a => a But again, we're talking about subtyping, and this isn't it. Consider the original problem, where we want a vector of objects of different concrete type. Haskell 98 doesn't help us here. The type Num a => [a] is inhabited by heterogeneous lists. The problem can be circumvented as described in the OP, or by using existential types. However, we still have hetergeneous lists, but the concrete type has been abstracted.