Reputation: 145
So in my code I have the data type Token declared as:
data Token = Char | Int
deriving (Show,Eq,Ord)
and a function readIfNumber declared as
readIfNumber :: Char -> Token
readIfNumber a
| isDigit a = Token (digitToInt a)
| otherwise = Token a
but when I try to compile, the console returns an error of "expecting type Token, but got Char" or "expecting Token, but got Int" when an Int should be viewed as a Token, according to my declaration of Token. What am I doing wrong here?
Upvotes: 2
Views: 132
Reputation: 120751
In a variant type, you always need to be explicit about which of the options you take. I.e. you need to “label” the two branches unambiguously, with constructors. Like,
data Token = CharToken Char | IntToken Int
When actually building a token from either a char or int, you thereto wrap it in the suitable constructor:
readIfNumber a
| isDigit a = IntToken $ digitToInt a
| otherwise = CharToken a
The reason this is required? Well, Haskell has full type erasure, i.e. types are completely traced, decided and optimised at compile time. At runtime, you wouldn't know whether the contained type was a char or int. Sometimes that's ok, namely when you have polymorphic actions. For example, length
really doesn't care what the type of the elements contained in a list is, as it only deals with the structure of the list.
In this case however, somebody who receives a Token
will need to know whether it's a char or int, to properly process it further. Hence the need to tag which type is contained.
Upvotes: 7