I have GADT like this one:
data TType a where
TInt :: TType Int
TBool :: TType Bool
I want to have a function like this one:
genTType :: Gen (TType a)
Which can generate random constructor of TType
type. I can do this simply by creating existentially qualified data type like
data AnyType = forall a . MkAnyType (TType a)
then generate random number from 0
to 1
(including) and create AnyType
depending on the integer value. Like this:
intToAnyType :: Int -> AnyType
intToAnyType 0 = MkAnyType TInt
intToAnyType 1 = MkAnyType TBool
intToAnyType _ = error "Impossible happened"
But this approach has couple drawbacks to me:
- No external type safety. If I add another constructor to
TType
data type I can forgot to fix tests and compiler won't warn me about this. - Compiler can't stop me from writing
intToAnyType 1 = MkAnyType TInt
. - I don't like this
error
.Int
type is too broad to me. It would be nice to make this pattern-matching exhaustive.
What can I do in Haskell to eliminate as much as possible drawbacks here? Preferably using generators from this module: