HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulegeneric-random-1.5.0.1Haskell2010

Generic.Random

GHC.Generics-based Test.QuickCheck.arbitrary generators.

Basic usage

{-# LANGUAGE DeriveGeneric #-}

data Foo = A | B | C  -- some generic data type
  deriving Generic

Derive instances of Test.QuickCheck.Arbitrary.

instance Arbitrary Foo where
  arbitrary = genericArbitrary uniform  -- Give a distribution of constructors.
  shrink = Test.QuickCheck.genericShrink  -- Generic shrinking is provided by the QuickCheck library.

Or derive standalone generators (the fields must still be instances of Test.QuickCheck.Arbitrary, or use custom generators).

genFoo :: Gen Foo
genFoo = genericArbitrary uniform
Using DerivingVia
{-# LANGUAGE DerivingVia, TypeOperators #-}

data Foo = A | B | C
  deriving Generic
  deriving Arbitrary via (GenericArbitraryU `AndShrinking' Foo)

For more information:

  • 27 types
  • 5 classes
  • 27 values

Arbitrary implementations

6 declarations

The suffixes for the variants have the following meanings:

  • U: pick constructors with uniform distribution (equivalent to passing uniform to the non-U variant).

  • Single: restricted to types with a single constructor.

  • G: with custom generators.

  • Rec: decrease the size at every recursive call (ensuring termination for (most) recursive types).

  • ': automatic discovery of "base cases" when size reaches 0.

valuegenericArbitrary
  1. :: GArbitrary UnsizedOpts a
  2. => Weights a

    List of weights for every constructor

  3. -> Gen a
#

Pick a constructor with a given distribution, and fill its fields with recursive calls to arbitrary.

Example
genericArbitrary (2 % 3 % 5 % ()) :: Gen a

Picks the first constructor with probability 2/10, the second with probability 3/10, the third with probability 5/10.

valuegenericArbitraryRec
  1. :: GArbitrary SizedOptsDef a
  2. => Weights a

    List of weights for every constructor

  3. -> Gen a
#

Decrease size at every recursive call, but don't do anything different at size 0.

genericArbitraryRec (7 % 11 % 13 % ()) :: Gen a

N.B.: This replaces the generator for fields of type [t] with listOf' arbitrary instead of Test.QuickCheck.listOf arbitrary (i.e., arbitrary for lists).

valuegenericArbitrary'
  1. :: (GArbitrary SizedOptsDef a, BaseCase a)
  2. => Weights a

    List of weights for every constructor

  3. -> Gen a
#

Decrease size to ensure termination for recursive types, looking for base cases once the size reaches 0.

genericArbitrary' (17 % 19 % 23 % ()) :: Gen a

N.B.: This replaces the generator for fields of type [t] with Test.QuickCheck.listOf' arbitrary instead of listOf arbitrary (i.e., arbitrary for lists).

With custom generators

Note about incoherence

The custom generator feature relies on incoherent instances, which can lead to surprising behaviors for parameterized types.

Example

For example, here is a pair type and a custom generator of Int (always generating 0).

data Pair a b = Pair a b
  deriving (Generic, Show)

customGen :: Gen Int
customGen = pure 0

The following two ways of defining a generator of Pair Int Int are not equivalent.

The first way is to use genericArbitrarySingleG to define a Gen (Pair a b) parameterized by types a and b, and then specialize it to Gen (Pair Int Int).

In this case, the customGen will be ignored.

genPair :: (Arbitrary a, Arbitrary b) => Gen (Pair a b)
genPair = genericArbitrarySingleG customGen

genPair' :: Gen (Pair Int Int)
genPair' = genPair
-- Will generate nonzero pairs

The second way is to define Gen (Pair Int Int) directly using genericArbitrarySingleG (as if we inlined genPair in genPair' above.

Then the customGen will actually be used.

genPair2 :: Gen (Pair Int Int)
genPair2 = genericArbitrarySingleG customGen
-- Will only generate (Pair 0 0)

In other words, the decision of whether to use a custom generator is done by comparing the type of the custom generator with the type of the field only in the context where genericArbitrarySingleG is being used (or any other variant with a G suffix).

In the first case above, those fields have types a and b, which are not equal to Int (or rather, there is no available evidence that they are equal to Int, even if they could be instantiated as Int later). In the second case, they both actually have type Int.

valuegenericArbitraryG
  1. :: GArbitrary (SetGens genList UnsizedOpts) a
  2. => genList
  3. -> Weights a
  4. -> Gen a
#

genericArbitrary with explicit generators.

Example
genericArbitraryG customGens (17 % 19 % ())

where, the generators for String and Int fields are overridden as follows, for example:

customGens :: Gen String :+ Gen Int
customGens =
  (filter (/= 'NUL') <$> arbitrary) :+
  (getNonNegative <$> arbitrary)
Note on multiple matches

Multiple generators may match a given field: the first will be chosen.

Specifying finite distributions

4 declarations
datadata Weights a
#

Trees of weights assigned to constructors of type a, rescaled to obtain a probability distribution.

Two ways of constructing them.

(x1 % x2 % ... % xn % ()) :: Weights a
uniform :: Weights a

Using (%), there must be exactly as many weights as there are constructors.

uniform is equivalent to (1 % ... % 1 % ()) (automatically fills out the right number of 1s).

Instances1WeightBuilder'
newtypenewtype W (c :: Symbol)
#

Type of a single weight, tagged with the name of the associated constructor for additional compile-time checking.

((9 :: W "Leaf") % (8 :: W "Node") % ())
Instances1Num
  • Num (W c)Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
method(%) :: c ~ First' w => W c -> Prec' w -> w
#

A binary constructor for building up trees of weights.

Custom generators

7 declarations

Custom generators can be specified in a list constructed with (:+), and passed to functions such as genericArbitraryG to override how certain fields are generated.

Example:

customGens :: Gen String :+ Gen Int
customGens =
  (filter (/= 'NUL') <$> arbitrary) :+
  (getNonNegative <$> arbitrary)

There are also different types of generators, other than Test.QuickCheck.Gen, providing more ways to select the fields the generator than by simply comparing types:

  • Test.QuickCheck.Gen a: override fields of type a;

  • Gen1 f: override fields of type f x for some x, requiring a generator for x;

  • Gen1_ f: override fields of type f x for some x, not requiring a generator for x;

  • FieldGen s a: override record fields named s, which must have type a;

  • ConstrGen c i a: override the field at index i of constructor c, which must have type a (0-indexed);

Multiple generators may match a given field: the first, leftmost generator in the list will be chosen.

datadata (:+) a b
#

Heterogeneous list of generators.

Constructors

  • a :+ binfixr 1
Instances4FindGen, TypeLevelGenList, TypeLevelGenList'
newtypenewtype FieldGen (s :: Symbol) a
#

Custom generator for record fields named s.

If there is a field named s with a different type, this will result in a type error.

Constructors

Instances2FindGen
  • a ~ a' => FindGen ('MatchCoh 'True) s (FieldGen sn a) gs a'Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic

    Matching custom generator for field s.

  • a ~ a' => FindGen ('Match 'INCOHERENT) ('S _fg _coh '(con, i, 'Just s)) (FieldGen s a) gs a'Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic

    Matching custom generator for field s.

newtypenewtype ConstrGen (c :: Symbol) (i :: Nat) a
#

Custom generator for the i-th field of the constructor named c. Fields are 0-indexed.

Constructors

Instances2FindGen
  • a ~ a' => FindGen ('MatchCoh 'True) s (ConstrGen c i a) gs a'Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic

    Matching custom generator for i-th field of constructor c.

  • a ~ a' => FindGen ('Match 'INCOHERENT) ('S _fg _coh '('Just c, i, s)) (ConstrGen c i a) gs a'Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic

    Matching custom generator for i-th field of constructor c.

newtypenewtype Gen1 (f :: Type -> Type)
#

Custom generators for "containers" of kind Type -> Type, parameterized by the generator for "contained elements".

A custom generator Gen1 f will be used for any field whose type has the form f x, requiring a generator of x. The generator for x will be constructed using the list of custom generators if possible, otherwise an instance Arbitrary x will be required.

Constructors

Instances2FindGen
newtypenewtype Gen1_ (f :: k -> Type)
#

Custom generators for unary type constructors that are not "containers", i.e., which don't require a generator of a to generate an f a.

A custom generator Gen1_ f will be used for any field whose type has the form f x.

Constructors

Instances2FindGen
  • f x ~ a' => FindGen ('MatchCoh 'True) s (Gen1_ f) gs a'Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • FindGen ('Match 'INCOHERENT) s (Gen1_ f) gs (f a)Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic

    Matching custom generator for non-container f.

Helpful combinators

3 declarations
valuelistOf' :: Gen a -> Gen [a]
#

An alternative to Test.QuickCheck.listOf that divides the size parameter by the length of the list. The length follows a geometric distribution of parameter 1/(sqrt size + 1).

valuelistOf1' :: Gen a -> Gen [a]
#

An alternative to Test.QuickCheck.listOf1 (nonempty lists) that divides the size parameter by the length of the list. The length (minus one) follows a geometric distribution of parameter 1/(sqrt size + 1).

Base cases for recursive types

2 declarations
valuewithBaseCase :: Gen a -> Gen a -> Gen a
#

Run the first generator if the size is positive. Run the second if the size is zero.

defaultGen `withBaseCase` baseCaseGen
classclass BaseCase a where
#

Custom instances can override the default behavior.

Methods

Instances1BaseCase

Full options

2 declarations
newtypenewtype Options (c :: Coherence) (s :: Sizing) genList
#

Type-level options for GArbitrary.

Note: it is recommended to avoid referring to the Options type explicitly in code, as the set of options may change in the future. Instead, use the provided synonyms (UnsizedOpts, SizedOpts, SizedOptsDef) and the setter SetOptions (abbreviated as (<+)).

Instances10HasGenerators, SetGens, SetOptions, SetSized, SetUnsized, CoherenceOf, …
  • HasGenerators (Options c s g)Defined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SetGens g (Options c s _g) = Options c s gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SetOptions c (Options _c s g) = Options c s gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SetOptions g (Options c s _g) = Options c s gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SetOptions s (Options c _s g) = Options c s gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SetSized (Options c s g) = Options c 'Sized gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SetUnsized (Options c s g) = Options c 'Unsized gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type CoherenceOf (Options c _s _g) = cDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type GeneratorsOf (Options _c _s g) = gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
  • type SizingOf (Options _c s _g) = sDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic

Setters

familytype family SetOptions (x :: k) o
#

Setter for Options.

This subsumes the other setters: SetSized, SetUnsized, SetGens.

Instances3SetOptions

Size modifiers

datadata Sizing
#

Whether to decrease the size parameter before generating fields.

The Sized option makes the size parameter decrease in the following way: - Constructors with one field decrease the size parameter by 1 to generate that field. - Constructors with more than one field split the size parameter among all fields; the size parameter is rounded down to then be divided equally.

Constructors

  • Sized

    Decrease the size parameter when running generators for fields

  • Unsized

    Don't touch the size parameter

Instances1SetOptions

Custom generators

familytype family SetGens g opts
#
Instances1SetGens
  • type SetGens g (Options c s _g) = Options c s gDefined in generic-random-1.5.0.1 · Generic.Random.Internal.Generic
valuesetGenerators :: genList -> Options c s g0 -> Options c s genList
#

Define the set of custom generators.

Note: for recursive types which can recursively appear inside lists or other containers, you may want to include a custom generator to decrease the size when generating such containers.

See also the Note about lists in Generic.Random.Tutorial#notelists.

Coherence options

datadata Coherence
#

For custom generators to work with parameterized types, incoherent instances must be used internally. In practice, the resulting behavior is what users want 100% of the time, so you should forget this option even exists.

Details

The default configuration of generic-random does a decent job if we trust GHC implements precisely the instance resolution algorithm as described in the GHC manual:

While that assumption holds in practice, it is overly context-dependent (to know the context leading to a particular choice, we must replay the whole resolution algorithm). In particular, this algorithm may find one solution, but it is not guaranteed to be unique: the behavior of the program is dependent on implementation details.

An notable property to consider of an implicit type system (such as type classes) is coherence: the behavior of the program is stable under specialization.

This sounds nice on paper, but actually leads to surprising behavior for generic implementations with parameterized types, such as generic-random.

To address that, the coherence property can be relaxd by users, by explicitly allowing some custom generators to be chosen incoherently. With appropriate precautions, it is possible to ensure a weaker property which nevertheless helps keep type inference predictable: when a solution is found, it is unique. (This is assuredly weaker, i.e., is not stable under specialization.)

Constructors

  • INCOHERENT

    Match custom generators incoherently.

  • COHERENT

    Match custom generators coherently by default (can be manually bypassed with Incoherent).

Instances1SetOptions

Common options

Advanced options

Generic classes

2 declarations

Newtypes for DerivingVia

10 declarations

These newtypes correspond to the variants of genericArbitrary above.

newtypenewtype GenericArbitrary (weights :: k) a
#

Pick a constructor with a given distribution, and fill its fields with recursive calls to arbitrary.

Example
data X = ...
  deriving Arbitrary via (GenericArbitrary '[2, 3, 5] X)

Picks the first constructor with probability 2/10, the second with probability 3/10, the third with probability 5/10.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitrary.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitraryU a
#

Pick every constructor with equal probability.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitraryU.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitrarySingle a
#

arbitrary for types with one constructor. Equivalent to GenericArbitraryU, with a stricter type.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitrarySingle.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitraryRec (weights :: k) a
#

Decrease size at every recursive call, but don't do anything different at size 0.

data X = ...
  deriving Arbitrary via (GenericArbitraryRec '[2, 3, 5] X)

N.B.: This replaces the generator for fields of type [t] with listOf' arbitrary instead of Test.QuickCheck.listOf arbitrary (i.e., arbitrary for lists).

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitraryRec.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitraryG (genList :: k) (weights :: k1) a
#

GenericArbitrary with explicit generators.

Example
data X = ...
  deriving Arbitrary via (GenericArbitraryG CustomGens '[2, 3, 5] X)

where, for example, custom generators to override String and Int fields might look as follows:

type CustomGens = CustomString :+ CustomInt
Note on multiple matches

Multiple generators may match a given field: the first will be chosen.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitraryG.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitraryUG (genList :: k) a
#

GenericArbitraryU with explicit generators. See also GenericArbitraryG.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitraryUG.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitrarySingleG (genList :: k) a
#

genericArbitrarySingle with explicit generators. See also GenericArbitraryG.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitrarySingleG.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitraryRecG (genList :: k) (weights :: k1) a
#

genericArbitraryRec with explicit generators. See also genericArbitraryG.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitraryRecG.

Instances3Eq, Show, Arbitrary
newtypenewtype GenericArbitraryWith (opts :: k) (weights :: k1) a
#

General generic generator with custom options.

This newtype does no shrinking. To add generic shrinking, use AndShrinking.

Uses genericArbitraryWith.

Instances3Eq, Show, Arbitrary
newtypenewtype AndShrinking (f :: k) a
#

Add generic shrinking to a newtype wrapper for Arbitrary, using genericShrink.

data X = ...
  deriving Arbitrary via (GenericArbitrary '[1,2,3] `AndShrinking' X)

Equivalent to:

instance Arbitrary X where
  arbitrary = genericArbitrary (1 % 2 % 3 % ())
  shrink = genericShrink

Constructors

Instances3Eq, Show, Arbitrary

Helpers typeclasses