This is probably another easy Haskell question. If I have some "nested" data types, such as in this example code:
data Place = Country
| State
| City String
deriving Show
data State = California
| NewYork
deriving Show
data Country = USA
| Canada
deriving Show
I can legally make a list such as [USA, Canada] of type [Country], or [California, NewYork] of type [State], or [City "a", City "b"] of type [Place].
What do I have to do to make a list such as [USA, NewYork]? NewYork is a State which is a Place, and USA is a Country which is a Place, but ghci sees USA so it assumes I am making a list of Countrys (and NewYork is a State, so the list fails).
I think I need some way to cast a Country or State to a Place, but I'm at a loss on how to accomplish this.
I'm trying to avoid throwing the data contained within State and Country into the Place type, which I know would make it work, but I've got a decent amount of real data that I'd rather not jumble up like that.
Lists are an algebraic datatype of two constructors, although with special syntax, as described in Section 3.7.
In Haskell, lists are a homogenous data structure. It stores several elements of the same type. That means that we can have a list of integers or a list of characters but we can't have a list that has a few integers and then a few characters.
In Haskell, types are how you describe the data your program will work with.
Here's a little more output that led me to figure out the problem:
*Main> [State, State]
[State,State]
*Main> :t State
State :: Place
*Main> :t NewYork
NewYork :: State
This seems to imply that the word "State" is a valid constructor for Place, and that the data State refers to a value of only California or NewYork.
If you change the program slightly, to:
data Place = Country Country
| State State
| City String
deriving Show
data State = California
| NewYork
deriving Show
data Country = USA
| Canada
deriving Show
then you can make a list such as [Country USA, State NewYork] which is properly of type [Place]. Using the same word twice as in the first example does not "bind" the State type together in the way I had thought it would.
Of course, using the constructor State State is just a matter of preference, I could just as easily do AmericanState State
within the Place type if I were so inclined.
{-# LANGUAGE ExistentialQuantification #-}
data GenericPlace = forall a. Show a => GenericPlace a
places :: [GenericPlace]
places = [GenericPlace USA, GenericPlace NewYork]
See the GHC user guide # 7.4.4 Existentially quantified data constructors for some restrictions with this approach.
There's a in-depth study of making usable heterogeneous collections in Haskell.
Strongly typed heterogeneous collections
A heterogeneous collection is a datatype that is capable of storing data of different types, while providing operations for look-up, update, iteration, and others. There are various kinds of heterogeneous collections, differing in representation, invariants, and access operations. We describe HList --- a Haskell library for strongly typed heterogeneous collections including extensible records. We illustrate HList's benefits in the context of type-safe database access in Haskell. The HList library relies on common extensions of Haskell 98. Our exploration raises interesting issues regarding Haskell's type system, in particular, avoidance of overlapping instances, and reification of type equality and type unification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With