I am trying to create a new data declaration called place.
It looks like this:
data place = United States | France | England | Germany | Mexico | Canada
My hope is to then use a function called cap to take the place to its capital like so:
cap :: place -> String
cap a = case a of
Spain -> "Madrid"
France -> "Paris"
England -> "London"
Germany -> "Berlin"
Mexico -> "Mexico City"
Canada -> "Ottawa"
_ -> undefined
However the last case, where I am attempting to catch all other entries that may not exist in the data declaration does not work. If I enter capital Wales
for instance in GHCI, I don't get an undefined response. Instead I get a not in scope error. Can someone help me with my confusion and perhaps provide a legitimate way of trying to catch other cases?
The problem isn't with how you handle missing cases - how you're doing it is fine. The problem is that the Wales
constructor simply does not exist. So just like when you try to use a variable or function that has not been defined, you get a compilation error. Your cap
function never even gets called, so no changes you could do to it, would affect this behaviour. There's nothing you can do to make code that uses non-existing constructors compile.
When you enter capital Wales
, there is no Wales
in scope. It is not possible for you to construct a value that does not exist. If you have covered every possible case, then you do not need a default case.
To riff on sepp2k's and singpolyma's answers, the point here is that Haskell's union types are exhaustive. When you define a union type with n cases, you are telling Haskell that those n cases are the only cases that exist for your type. As singpolyma points out, you've told Haskell that other cases don't even exist.
This has benefits and drawbacks. Exhaustiveness means that you and the compiler can guarantee that your functions are handling all possible inputs that they will be given. The drawback is that the set of cases is fixed at compilation time.
The simplest alternative here is two-part:
So you could represent nations and cities like this:
-- Since there are infinitely many different strings you could construct at runtime,
-- there are also infinitely many different Cities and Nations...
data City = City String deriving (Eq, Ord, Show)
data Nation = Nation String deriving (Eq, Ord, Show
The simplest key/value mapping type is [(k, v)]
, often known as an association list. It has of course an O(n) lookup time. A better one is to use Data.Map
, which comes with the Haskell Platform.
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