Safe Haskell | None |
---|---|

Language | Haskell2010 |

Simple `Generics`

-based `arbitrary`

generators.

Here is an example. Define your type.

data Tree a = Leaf a | Node (Tree a) (Tree a)

Derive `Generic`

.

deriving 'Generic' -- Turn on the DeriveGeneric extension

Pick an arbitrary implementation.

instance Arbitrary a => Arbitrary (Tree a) where arbitrary = genericArbitraryFrequency [9, 8]

`arbitrary :: `

picks a `Gen`

(Tree a)`Leaf`

with probability 9/17, or a
`Node`

with probability 8/17, and recursively fills their fields with
`arbitrary`

.

- genericArbitrary :: (Generic a, GA Unsized (Rep a)) => Gen a
- genericArbitraryFrequency :: (Generic a, GA Unsized (Rep a)) => [Int] -> Gen a
- genericArbitraryFrequency' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => [Int] -> Gen a
- genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => Gen a
- data Nat
- type BaseCases' n a = (Generic a, BaseCases n (Rep a))
- class BaseCases n f

# Documentation

genericArbitrary :: (Generic a, GA Unsized (Rep a)) => Gen a Source #

Pick a constructor with uniform probability, and fill its fields recursively.

An equivalent definition for `Tree`

is:

genericArbitrary :: Arbitrary a => Gen (Tree a) genericArbitrary = oneof [ Leaf <$> arbitrary -- Uses Arbitrary a , Node <$> arbitrary <*> arbitrary -- Uses Arbitrary (Tree a) ]

Note that for many types, `genericArbitrary`

tends to produce big values.
For instance for `Tree a`

values are finite but the average number of
`Leaf`

and `Node`

constructors is infinite.

genericArbitraryFrequency Source #

This allows to specify the probability distribution of constructors as a list of weights, in the same order as the data type definition.

An equivalent definition for `Tree`

is:

genericArbitraryFrequency :: Arbitrary a => [Int] -> Gen (Tree a) genericArbitraryFrequency [x, y] = frequency [ (x, Leaf <$> arbitrary) , (y, Node <$> arbitrary <*> arbitrary) ]

genericArbitraryFrequency' Source #

:: forall (n :: Nat). (Generic a, GA (Sized n) (Rep a)) | |

=> [Int] | List of weights for every constructor |

-> Gen a |

The size parameter of `Gen`

is divided among the fields of the chosen
constructor. When it reaches zero, the generator selects a finite term
whenever it can find any of the given type.

The type of `genericArbitraryFrequency'`

has an ambiguous `n`

parameter; it
is a type-level natural number of type `Nat`

. That number determines the
maximum *depth* of terms that can be used to end recursion.

You'll need the `TypeApplications`

and `DataKinds`

extensions.

genericArbitraryFrequency' @n weights

With `n ~ '`

, the generator looks for a simple nullary constructor. If none
exist at the current type, as is the case for our `Z`

`Tree`

type, it carries on
as in `genericArbitraryFrequency`

.

genericArbitraryFrequency' @'Z :: Arbitrary a => [Int] -> Gen (Tree a) genericArbitraryFrequency' @'Z [x, y] = frequency [ (x, Leaf <$> arbitrary) , (y, scale (`div` 2) $ Node <$> arbitrary <*> arbitrary) ] -- 2 because Node is 2-ary.

Here is another example:

data Tree' = Leaf1 | Leaf2 | Node3 Tree' Tree' Tree' deriving Generic instance Arbitrary Tree' where arbitrary = genericArbitraryFrequency' @'Z [1, 2, 3]

`genericArbitraryFrequency'`

is equivalent to:

genericArbitraryFrequency' @'Z :: [Int] -> Gen Tree' genericArbitraryFrequency' @'Z [x, y, z] = sized $ \n -> if n == 0 then -- If the size parameter is zero, the non-nullary alternative is discarded. frequency $ [ (x, return Leaf1) , (y, return Leaf2) ] else frequency $ [ (x, return Leaf1) , (y, return Leaf2) , (z, resize (n `div` 3) node) ] -- 3 because Node3 is 3-ary where node = Node3 <$> arbitrary <*> arbitrary <*> arbitrary

To increase the chances of termination when no nullary constructor is directly
available, such as in `Tree`

, we can pass a larger depth `n`

. The effectiveness
of this parameter depends on the concrete type the generator is used for.

For instance, if we want to generate a value of type `Tree ()`

, there is a
value of depth 1 (represented by `'`

) that we can use to end
recursion: `S`

'`Z`

`Leaf ()`

.

genericArbitraryFrequency' @('S 'Z) :: [Int] -> Gen (Tree ()) genericArbitraryFrequency' @('S 'Z) [x, y] = sized $ \n -> if n == 0 then return (Leaf ()) else frequency [ (x, Leaf <$> arbitrary) , (y, scale (`div` 2) $ Node <$> arbitrary <*> arbitrary) ]

Because the argument of `Tree`

must be inspected in order to discover
values of type `Tree ()`

, we incur some extra constraints if we want
polymorphism.

`FlexibleContexts`

and `UndecidableInstances`

are also required.

instance (Arbitrary a, Generic a, BaseCases 'Z (Rep a)) => Arbitrary (Tree a) where arbitrary = genericArbitraryFrequency' @('S 'Z) [1, 2]

A synonym is provided for brevity.

instance (Arbitrary a, BaseCases' 'Z a) => Arbitrary (Tree a) where arbitrary = genericArbitraryFrequency' @('S 'Z) [1, 2]

genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => Gen a Source #

Like `genericArbitraryFrequency'`

, but with uniformly distributed
constructors.

A `BaseCases n (`

constraint basically provides the list of values
of type `Rep`

a)`a`

with depth at most `n`

.

BaseCases n U1 Source # | |

(BaseCases n f, BaseCases n g) => BaseCases n ((:*:) f g) Source # | |

(BaseCases n f, BaseCases n g) => BaseCases n ((:+:) f g) Source # | |

BaseCases Z (K1 i c) Source # | |

BaseCases n f => BaseCases n (M1 i c f) Source # | |

(Generic c, BaseCases n (Rep c)) => BaseCases (S n) (K1 i c) Source # | |