Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safest way to generate random GADT with Hedgehog (or any other property-based testing framework)

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:

  • https://hackage.haskell.org/package/hedgehog-0.5.1/docs/Hedgehog-Gen.html
like image 548
Shersh Avatar asked Jan 13 '18 16:01

Shersh


1 Answers

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]
like image 64
Li-yao Xia Avatar answered Sep 30 '22 10:09

Li-yao Xia