generic-random-1.5.0.1: src/Generic/Random.hs
-- | "GHC.Generics"-based 'Test.QuickCheck.arbitrary' generators.
--
-- = Basic usage
--
-- @
-- {-\# LANGUAGE DeriveGeneric \#-}
--
-- data Foo = A | B | C -- some generic data type
-- deriving 'GHC.Generics.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 'GHC.Generics.Generic'
-- deriving Arbitrary via ('GenericArbitraryU' `'AndShrinking'` Foo)
-- @
--
-- For more information:
--
-- - "Generic.Random.Tutorial"
-- - http://blog.poisson.chat/posts/2018-01-05-generic-random-tour.html
{-# LANGUAGE ExplicitNamespaces #-}
module Generic.Random
(
-- * Arbitrary implementations
-- | 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.
genericArbitrary
, genericArbitraryU
, genericArbitrarySingle
, genericArbitraryRec
, genericArbitrary'
, genericArbitraryU'
-- ** 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@.
, genericArbitraryG
, genericArbitraryUG
, genericArbitrarySingleG
, genericArbitraryRecG
-- * Specifying finite distributions
, Weights
, W
, (%)
, uniform
-- * Custom generators
-- | 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.
, (:+) (..)
, FieldGen (..)
, fieldGen
, ConstrGen (..)
, constrGen
, Gen1 (..)
, Gen1_ (..)
-- * Helpful combinators
, listOf'
, listOf1'
, vectorOf'
-- * Base cases for recursive types
, withBaseCase
, BaseCase (..)
-- * Full options
, Options ()
, genericArbitraryWith
-- ** Setters
, SetOptions
, type (<+)
, setOpts
-- ** Size modifiers
, Sizing (..)
, SetSized
, SetUnsized
, setSized
, setUnsized
-- ** Custom generators
, SetGens
, setGenerators
-- ** Coherence options
, Coherence (..)
, Incoherent (..)
-- ** Common options
, SizedOpts
, sizedOpts
, SizedOptsDef
, sizedOptsDef
, UnsizedOpts
, unsizedOpts
-- *** Advanced options
-- | See 'Coherence'
, CohUnsizedOpts
, cohUnsizedOpts
, CohSizedOpts
, cohSizedOpts
-- * Generic classes
, GArbitrary
, GUniformWeight
-- * Newtypes for DerivingVia
-- | These newtypes correspond to the variants of 'genericArbitrary' above.
, GenericArbitrary (..)
, GenericArbitraryU (..)
, GenericArbitrarySingle (..)
, GenericArbitraryRec (..)
, GenericArbitraryG (..)
, GenericArbitraryUG (..)
, GenericArbitrarySingleG (..)
, GenericArbitraryRecG (..)
, GenericArbitraryWith (..)
, AndShrinking (..)
-- ** Helpers typeclasses
, TypeLevelGenList (..)
, TypeLevelOpts (..)
) where
import Generic.Random.Internal.BaseCase
import Generic.Random.Internal.Generic
import Generic.Random.DerivingVia