Paulo Rodrigues
Paulo Rodrigues

Reputation: 11

How do i check what is the kind of an element from a data type variable in haskell?

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.

Upvotes: 1

Views: 362

Answers (3)

Will Ness
Will Ness

Reputation: 71065

The data type itself already tells you what it is. So you use it as an Int like this:

foo :: (Int -> r) -> Token -> Maybe r
foo f (Number i) = Just (f i)
foo _  _         = Nothing

In case it was an Int, we use it; and otherwise, we don't.

Upvotes: 0

Robin Zigmond
Robin Zigmond

Reputation: 18249

@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.

Upvotes: 1

chepner
chepner

Reputation: 531055

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

Upvotes: 6

Related Questions