-- | "GHC.Generics"-based 'Test.QuickCheck.arbitrary' generators.
--
-- = Basic usage
--
-- @
-- 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
-- @
--
-- Or derive standalone generators (the fields must still be instances of
-- 'Test.QuickCheck.Arbitrary', or use custom generators).
--
-- @
-- genFoo :: Gen Foo
-- genFoo = 'genericArbitrary' 'uniform'
-- @
--
-- For more information:
--
-- - "Generic.Random.Tutorial"
-- - http://blog.poisson.chat/posts/2018-01-05-generic-random-tour.html

{-# LANGUAGE CPP #-}

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
  , (:+) (..)
#if __GLASGOW_HASKELL__ >= 800
  , FieldGen (..)
  , fieldGen
  , ConstrGen (..)
  , constrGen
#endif
  , Gen1 (..)
  , Gen1_ (..)

    -- * Helpful combinators
  , listOf'
  , listOf1'
  , vectorOf'

    -- * Base cases for recursive types
  , withBaseCase
  , BaseCase (..)

    -- * Full options
  , Options ()
  , genericArbitraryWith

    -- ** Size modifiers
  , Sizing (..)
  , setSized
  , setUnsized

    -- ** Custom generators
  , SetGens
  , setGenerators

    -- ** Common options
  , SizedOpts
  , sizedOpts
  , SizedOptsDef
  , sizedOptsDef
  , UnsizedOpts
  , unsizedOpts

    -- * Generic classes
  , GArbitrary
  , GUniformWeight

  ) where

import Generic.Random.Internal.BaseCase
import Generic.Random.Internal.Generic