I have a data type like this:
data Token = Foo | Bar | Number Int deriving (Show, Eq)
And a variable:
a = Number 20
How can i test if this variable is a Number? Its type is Token, but i would like to see if it can work as an int.
CodePudding user response:
You use pattern matching. An an example, here's a simple predicate that will return True
if it's a value created by Number
, and False
otherwise.
isNumber :: Token -> Bool
isNumber (Number _) = True
isNumber _ = False
CodePudding user response:
@Chepner has already given how to test whether a Token
value uses the Number
constructor or not. But I feel a bit more can be said about how to extract the Int
value from it, which seems to be what you want when you say you "would like to see if it can work as an int.". Because if you use chepner's isNumber
function and it returns True
, you can't get that Int
out without pattern matching once again. So you might as well combine the two steps into one.
Here is a simple way to do that:
getNumber :: Value -> Maybe Int
getNumber (Number n) = Just n
getNumber _ = Nothing
Notice the type here - this function can't return an Int
because you don't know that the value you're testing on contains one!* Notice also how similar it is in structure with the isNumber
function - and this still allows you easily to do different things with the different cases, like this
case (getNumber someValue) of
Just n -> - - do something with n
Nothing -> - - handle the other cases
Note that this assumes you want to handle all non-numeric constructors the same way. If you want to do something different with each, then you don't need getNumber
or isNumber
but can just pattern match directly on someValue
and do whatever you need in each case.
*you might want to provide a default in this case, like 0. But even then I would suggest using the same getNumber
function above and combining it with the library function fromMaybe
- ie getWithDefault = fromMaybe 0 . getNumber
.