Safe Haskell | None |
---|---|
Language | Haskell2010 |
Generic.Random.Generic
Description
Simple Generics
-based arbitrary
generators.
Here is an example. Define your type.
data Tree a = Leaf a | Node (Tree a) (Tree a) deriving Generic
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 :: forall a. (Generic a, GA Unsized (Rep a)) => Gen a
- genericArbitraryFrequency :: forall a. (Generic a, GA Unsized (Rep a)) => [Int] -> Gen a
- genericArbitraryFrequency' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> [Int] -> Gen a
- genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> Gen a
- data Z = Z
- data S n = S n
- type BaseCases' n a = (Generic a, BaseCases n (Rep a))
- class BaseCases n f
Arbitrary implementations
genericArbitrary :: forall a. (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 #
Arguments
:: (Generic a, GA (Sized n) (Rep a)) | |
=> n | |
-> [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 natural number n
determines the maximum depth of terms that can be
used to end recursion.
It is encoded using
and Z
:: Z
.S
:: n -> S
n
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)) => n -> Gen a Source #
Like genericArbitraryFrequency'
, but with uniformly distributed
constructors.
Type-level natural numbers
Successor
Constructors
S n |
Generic class for finite values
A BaseCases n (
constraint basically provides the list of values
of type Rep
a)a
with depth at most n
.
Minimal complete definition
Instances
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 # | |