I'm having trouble defining a new data type in Haskell.
I'm trying to create a data type NumPair
that will be a tuple containing either two integers, or an integer and another NumPair
.
So for instance, (2, 2), (0, 5), (1, (2, 3)) and (0, (4, (3, 121)))
should all be valid NumPairs
.
This is the code I've written to try to do this:
data NumPair = (Int, Int) | (Int, NumPair) deriving (Eq, Show)
Can someone explain why this doesn't work and what I should do instead, please?
In general, we define a new data type by using the data keyword, followed by the name of the type we're defining. The type has to begin with a capital letter to distinguish it from normal expression names. To start defining our type, we must provide a constructor.
A tuple is a fixed-length coupling of values, written in parentheses with the values separated by commas. One way to use this is to pass all parameters into a function as one value, rather than the curried functions we've seen so far.
You can combine multiple types with an and (for example, a name is a String and another String ), or you can combine types with an or (for example, a Bool is a True data constructor or a False data constructor). Types that are made by combining other types with an and are called product types.
A tuple is a sequence of values. The values can be of any type, and they are indexed by an integer, so tuples are not like lists. Tuples are immutable which means you cannot add more elements to the tuple as the program runs.
You need to add constructor names for each alternative:
data NumPair = Pair (Int, Int) | More (Int, NumPair) deriving (Eq, Show)
Those constructor names are what let you pattern match on the data type like so:
f :: NumPair -> A
f (Pair (x, y )) = ...
f (More (x, np)) = ...
You can then build a value using the constructors to (which is why they are called constructors):
myNumPair :: NumPair
myNumPair = More (1, More (2, Pair (3, 4)))
There are two other ways you can improve your type. Haskell constructors have built-in support for multiple fields, so rather than using a tuple you can just list the values directly in the constructor like this:
data NumPair = Pair Int Int | More Int NumPair deriving (Eq, Show)
Another way you can improve upon it is to recognize that you've just written the type for a non-empty list. The best implementation for non-empty lists resides in Data.List.NonEmpty
of the semigroups
package, which you can find here.
Then your type just becomes:
type NumPair = NonEmpty Int
... and you get a bunch of function on non-empty lists for free from that module.
Edit: n.m. brought to my attention that what you probably wanted was:
data NumPair = Pair (Int, Int) | More ((Int, Int), NumPair)
... which is equivalent to:
type NumPair = NonEmpty (Int, Int)
The difference is that this latter one lets you append pairs of integers, where as the previous one that followed your question's type only lets you append integers.
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