7

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:

  1. 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.
  2. Compiler can't stop me from writing intToAnyType 1 = MkAnyType TInt.
  3. 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:

Shersh
  • 9,019
  • 3
  • 33
  • 61
  • There is nothing the typechecker can do to help you with points 2 or 3. The compiler can't prevent you writing `intToAnyType 1 = MkAnyType TInt` because the type system isn't strong enough to express the invariant that the output constructor must correspond to the input integer in some way; this requires dependent types. Nor can you avoid a partial function, for the same reason (you can of course return `Maybe AnyType` instead). For #1 you can use [`tagToEnum#`](https://hackage.haskell.org/package/ghc-prim-0.4.0.0/docs/src/GHC-Prim.html#tagToEnum%23) (assuming your type will indeed be an enum) – user2407038 Jan 13 '18 at 18:57
  • 2
    @user2407038 Type system is not strong enough. But I believe in tested libraries :) For example, if only I could automatically derive `Enum` and `Bounded` for my GADT, I could use `enumBounded` generator from Hedgehog: https://hackage.haskell.org/package/hedgehog-0.5.1/docs/Hedgehog-Gen.html#v:enumBounded So, delegating as much as possible work to tested generating libraries is quite a solution to me. – Shersh Jan 13 '18 at 19:50

1 Answers1

4

Generating genTType with Template Haskell is probably your best bet to automate maintenance of the generators, because there is no generic programming support for GADTs.

For your last point, instead of generating an integer and then mapping it to a value, use oneof or element.

 element [MkAnyType TInt, MkAnyType TBool]
Li-yao Xia
  • 31,896
  • 2
  • 33
  • 56