Reputation: 5412
Let us say we have
data D = X Int | Y Int Int | Z String
I wish to have a function getDConst
getDConst :: D -> String
that returns either "X", "Y", or "Z", according to the data constructor used for its input. Is there a generic way to write this without having to do case
on every data constructor? (I am ok with solutions relying on Data.Typeable
or something similar)
Upvotes: 25
Views: 3729
Reputation: 470
I have a much basic answer to the question without going through imports or whatever. It's Just a simple mere function.
let's say I have the following data. The repetitive Int in the data definition is intentional because I will use the don't care symbol afterwards:
data YES_NO_CANCEL = YES Int | NO Int Int | CANCEL Int Int Int
then you can make a function as :
extractDataType :: YES_NO_CANCEL -> String
extractDataType (YES _) = "YES"
extractDataType (NO _ _) = "NO"
extractDataType (CANCEL _ _ _) = "CANCEL"
Upvotes: -1
Reputation: 62848
If you don't want to use Typeable
, you can also do this with Show
.
getDConst :: D -> String
getDConst = head . words . show
Show
will not output all the fields, because it is lazy. You can test it runing this code in ghci
:
Prelude> data D = D [Int] deriving (Show)
Prelude> getDConst $ D [1..]
"D"
Upvotes: 11
Reputation: 5412
Found the solution myself, but leaving this question to help others:
import Data.Data
data D = X Int | Y Int Int deriving (Data,Typeable)
let result = show $ toConstr (X 3) -- result contains what we wanted
Upvotes: 26