Safe Haskell | None |
---|---|
Language | Haskell2010 |
- 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
- newtype Freq sized a = Freq {}
- newtype Gen' sized a = Gen' {}
- data Sized :: Nat -> *
- data Unsized
- liftGen :: Gen a -> Freq sized a
- class GA sized f where
- gArbitrarySingle :: forall sized f p. GA sized f => Gen' sized (f p)
- class GASum sized f where
- class GAProduct f where
- newtype Tagged a b = Tagged {
- unTagged :: b
- data Nat
- class BaseCases n f where
- type BaseCases' n a = (Generic a, BaseCases n (Rep a))
- baseCases' :: forall n f p. BaseCases n f => Tagged n [f p]
Random generators
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.
Internal
class GA sized f where Source #
Generic Arbitrary
GA sized U1 Source # | |
Arbitrary c => GA sized (K1 i c) Source # | |
(GASum Unsized f, GASum Unsized g) => GA Unsized ((:+:) f g) Source # | |
(GA Unsized f, GA Unsized g) => GA Unsized ((:*:) f g) Source # | |
GA sized f => GA sized (M1 i c f) Source # | |
(GAProduct f, GAProduct g) => GA (Sized n) ((:*:) f g) Source # | |
(GASum (Sized n) f, GASum (Sized n) g, BaseCases n f, BaseCases n g) => GA (Sized n) ((:+:) f g) Source # | |
gArbitrarySingle :: forall sized f p. GA sized f => Gen' sized (f p) Source #
class BaseCases n f where Source #
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 # | |
baseCases' :: forall n f p. BaseCases n f => Tagged n [f p] Source #