HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulehedgehog-1.7Haskell2010

Hedgehog.Internal.Gen

  • 4 types
  • 1 class
  • 99 values
  • Packagehedgehog-1.7
  • Exports104
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceGen.hs

Transformer

3 declarations
newtypenewtype GenT (m :: Type -> Type) a
#

Monad transformer which can generate random values of a.

Constructors

Instances28MonadTrans, MMonad, MonadTransDistributive, MFunctor, MonadError, MonadReader, …
classclass (Monad m, Monad (GenBase m)) => MonadGen (m :: Type -> Type) where
#

Class of monads which can generate input data for tests.

Associated types

Methods

Instances9MonadGen, …

Combinators

1 declaration

Shrinking

valueshrink :: MonadGen m => (a -> [a]) -> m a -> m a
#

Apply a shrinking function to a generator.

This will give the generator additional shrinking options, while keeping the existing shrinks intact.

valueprune :: MonadGen m => m a -> m a
#

Throw away a generator's shrink tree.

Size

valuesmall :: MonadGen m => m a -> m a
#

Make a generator smaller by scaling its size parameter.

valueresize :: MonadGen m => Size -> m a -> m a
#

Override the size parameter. Returns a generator which uses the given size instead of the runtime-size parameter.

valuesized :: MonadGen m => (Size -> m a) -> m a
#

Construct a generator that depends on the size parameter.

Integral

valueintegral :: (MonadGen m, Integral a) => Range a -> m a
#

Generates a random integral number in the given [inclusive,inclusive] range.

When the generator tries to shrink, it will shrink towards the origin of the specified Range.

For example, the following generator will produce a number between 1970 and 2100, but will shrink towards 2000:

integral (Range.constantFrom 2000 1970 2100) :: Gen Int

Some sample outputs from this generator might look like:

=== Outcome ===
1973
=== Shrinks ===
2000
1987
1980
1976
1974
=== Outcome ===
2061
=== Shrinks ===
2000
2031
2046
2054
2058
2060
valueintegral_ :: (MonadGen m, Integral a) => Range a -> m a
#

Generates a random integral number in the [inclusive,inclusive] range.

This generator does not shrink.

valueint :: MonadGen m => Range Int -> m Int
#

Generates a random machine integer in the given [inclusive,inclusive] range.

This is a specialization of integral, offered for convenience.

valueint8 :: MonadGen m => Range Int8 -> m Int8
#

Generates a random 8-bit integer in the given [inclusive,inclusive] range.

This is a specialization of integral, offered for convenience.

valueint16 :: MonadGen m => Range Int16 -> m Int16
#

Generates a random 16-bit integer in the given [inclusive,inclusive] range.

This is a specialization of integral, offered for convenience.

valueint32 :: MonadGen m => Range Int32 -> m Int32
#

Generates a random 32-bit integer in the given [inclusive,inclusive] range.

This is a specialization of integral, offered for convenience.

valueint64 :: MonadGen m => Range Int64 -> m Int64
#

Generates a random 64-bit integer in the given [inclusive,inclusive] range.

This is a specialization of integral, offered for convenience.

valueword :: MonadGen m => Range Word -> m Word
#

Generates a random machine word in the given [inclusive,inclusive] range.

This is a specialization of integral, offered for convenience.

Floating-point

valuerealFloat :: (MonadGen m, RealFloat a) => Range a -> m a
#

Generates a random floating-point number in the [inclusive,exclusive) range.

This generator works the same as integral, but for floating point numbers.

valuerealFrac_ :: (MonadGen m, RealFrac a) => Range a -> m a
#

Generates a random fractional number in the [inclusive,exclusive) range.

This generator does not shrink.

valuefloat :: MonadGen m => Range Float -> m Float
#

Generates a random floating-point number in the [inclusive,exclusive) range.

This is a specialization of realFloat, offered for convenience.

Enumeration

valueenum :: (MonadGen m, Enum a) => a -> a -> m a
#

Generates an element from an enumeration.

This generator shrinks towards the first argument.

For example:

enum 'a' 'z' :: Gen Char
valueenumBounded :: (MonadGen m, Enum a, Bounded a) => m a
#

Generates a random value from a bounded enumeration.

This generator shrinks towards minBound.

For example:

enumBounded :: Gen Bool

This is implemented in terms of the Enum class, and thus may be partial for integral types larger than Int, e.g. Word64.

valuebool_ :: MonadGen m => m Bool
#

Generates a random boolean.

This generator does not shrink.

Characters

valuehexit :: MonadGen m => m Char
#

Generates an ASCII hexit: '0..9', 'a'..'f', 'A'..'F'

valuealphaNum :: MonadGen m => m Char
#

Generates an ASCII letter or digit: 'a'..'z', 'A'..'Z', '0'..'9'

valueunicode :: MonadGen m => m Char
#

Generates a Unicode character, excluding noncharacters and invalid standalone surrogates: '0..1114111' (excluding '55296..57343', '65534', '65535')

valueunicodeAll :: MonadGen m => m Char
#

Generates a Unicode character, including noncharacters and invalid standalone surrogates: '0..1114111'

Strings

Choice

valueconstant :: MonadGen m => a -> m a
#

Trivial generator that always produces the same element.

This is another name for pure / return.

valueelement :: (HasCallStack, Foldable f, MonadGen m) => f a -> m a
#

Randomly selects one of the elements in the list.

This generator shrinks towards the first element in the list.

The input list must be non-empty.

valueelement_ :: (HasCallStack, MonadGen m) => [a] -> m a
#

Randomly selects one of the elements in the list.

This generator does not shrink the choice of element.

The input list must be non-empty.

valuechoice :: (HasCallStack, MonadGen m) => [m a] -> m a
#

Randomly selects one of the generators in the list.

This generator shrinks towards the first generator in the list.

The input list must be non-empty.

valuefrequency :: (HasCallStack, MonadGen m) => [(Int, m a)] -> m a
#

Uses a weighted distribution to randomly select one of the generators in the list.

This generator shrinks towards the first generator in the list.

The input list must be non-empty.

valuerecursive :: MonadGen m => ([m a] -> m a) -> [m a] -> [m a] -> m a
#

Modifies combinators which choose from a list of generators, like choice or frequency, so that they can be used in recursive scenarios.

This combinator modifies its target to select one of the generators in either the non-recursive or the recursive list. When a selection is made from the recursive list, the Size is halved. When the Size gets to one or less, selections are no longer made from the recursive list, this ensures termination.

A good example of where this might be useful is abstract syntax trees:

data Expr =
    Var String
  | Lam String Expr
  | App Expr Expr

-- Assuming we have a name generator
genName :: MonadGen m => m String

-- We can write a generator for expressions
genExpr :: MonadGen m => m Expr
genExpr =
  Gen.recursive Gen.choice [
      -- non-recursive generators
      Var <$> genName
    ] [
      -- recursive generators
      Gen.subtermM genExpr (x -> Lam <$> genName <*> pure x)
    , Gen.subterm2 genExpr genExpr App
    ]

If we wrote the above example using only choice, it is likely that it would fail to terminate. This is because for every call to genExpr, there is a 2 in 3 chance that we will recurse again.

Conditional

valueensure :: MonadGen m => (a -> Bool) -> m a -> m a
#

Discards the generator if the generated value does not satisfy the predicate.

valuefilter :: (MonadGen m, GenBase m ~ Identity) => (a -> Bool) -> m a -> m a
#

Generates a value that satisfies a predicate.

Shrinks of the generated value will also satisfy the predicate. From the original generator's shrink tree, any values that fail the predicate will be removed, but any subsequent shrinks that satisfy it will be retained. Compared to filter, shrinking may be slower but will be optimal.

It's possible that the predicate will never pass, or will only pass at a larger size than we're currently running at. To avoid looping forever, we limit the number of retries, and grow the size with each retry. If we retry too many times then the whole generator is discarded.

valuemapMaybe
  1. :: (MonadGen m, GenBase m ~ Identity)
  2. => a -> Maybe b
  3. -> m a
  4. -> m b
#

Generates a value which is the result of the given function returning a Just.

The original generator's shrink tree will be retained, with values returning Nothing removed. Subsequent shrinks of those values will be retained. Compared to mapMaybeT, shrinking may be slower but will be optimal.

It's possible that the function will never return Just, or will only do so a larger size than we're currently running at. To avoid looping forever, we limit the number of retries, and grow the size with each retry. If we retry too many times then the whole generator is discarded.

valuefilterT :: MonadGen m => (a -> Bool) -> m a -> m a
#

Generates a value that satisfies a predicate.

Shrinks of the generated value will also satisfy the predicate. From the original generator's shrink tree, any values that fail the predicate will be removed, along with their subsequent shrinks. Compared to filter, shrinking may be faster but may also be less optimal.

The type is also more general, because the shrink behavior from filter would force the entire shrink tree to be evaluated when applied to an impure tree.

This is essentially:

  filterT p gen = mfilter p gen <|> filterT p gen

But that could loop forever, if the predicate will never pass or will only pass at a larger size than we're currently running at. We differ from the above in keeping some state to avoid that. We limit the number of retries, and grow the size with each retry. If we retry too many times then the whole generator is discarded.

valuemapMaybeT :: MonadGen m => (a -> Maybe b) -> m a -> m b
#

Generates a value which is the result of the given function returning a Just.

The original generator's shrink tree will be retained, with values returning Nothing removed. Subsequent shrinks of those values will be retained. Compared to mapMaybeT, shrinking may be slower but will be optimal.

The type is also more general, because the shrink behavior from mapMaybe would force the entire shrink tree to be evaluated when applied to an impure tree.

It's possible that the function will never return Just, or will only do so a larger size than we're currently running at. To avoid looping forever, we limit the number of retries, and grow the size with each retry. If we retry too many times then the whole generator is discarded.

Collections

valueeither :: MonadGen m => m a -> m b -> m (Either a b)
#

Generates either an a or a b.

As the size grows, this generator generates Rights more often than Lefts.

valueeither_ :: MonadGen m => m a -> m b -> m (Either a b)
#

Generates either an a or a b, without bias.

This generator generates as many Rights as it does Lefts.

valueset :: (MonadGen m, Ord a) => Range Int -> m a -> m (Set a)
#

Generates a set using a Range to determine the length.

This may fail to generate anything if the element generator cannot produce a large enough number of unique items to satify the required set size.

valuemap :: (MonadGen m, Ord k) => Range Int -> m (k, v) -> m (Map k v)
#

Generates a map using a Range to determine the length.

This may fail to generate anything if the keys produced by the generator do not account for a large enough number of unique items to satify the required map size.

Subterms

valuefreeze :: MonadGen m => m a -> m (a, m a)
#

Freeze the size and seed used by a generator, so we can inspect the value which it will produce.

This is used for implementing list and subtermMVec. It allows us to shrink the list itself before trying to shrink the values inside the list.

valuesubterm :: MonadGen m => m a -> (a -> a) -> m a
#

Constructs a generator from a sub-term generator.

Shrinks to the sub-term if possible.

valuesubtermM :: MonadGen m => m a -> (a -> m a) -> m a
#

Constructs a generator from a sub-term generator.

Shrinks to the sub-term if possible.

valuesubterm2 :: MonadGen m => m a -> m a -> (a -> a -> a) -> m a
#

Constructs a generator from two sub-term generators.

Shrinks to one of the sub-terms if possible.

valuesubtermM2 :: MonadGen m => m a -> m a -> (a -> a -> m a) -> m a
#

Constructs a generator from two sub-term generators.

Shrinks to one of the sub-terms if possible.

valuesubterm3 :: MonadGen m => m a -> m a -> m a -> (a -> a -> a -> a) -> m a
#

Constructs a generator from three sub-term generators.

Shrinks to one of the sub-terms if possible.

valuesubtermM3 :: MonadGen m => m a -> m a -> m a -> (a -> a -> a -> m a) -> m a
#

Constructs a generator from three sub-term generators.

Shrinks to one of the sub-terms if possible.

Combinations & Permutations

valuesubsequence :: MonadGen m => [a] -> m [a]
#

Generates a random subsequence of a list.

For example:

Gen.print (Gen.subsequence [1..5])
=== Outcome ===
[1,2,4]
=== Shrinks ===
[]
[2,4]
[1,4]
[1,2]
valuesubset :: MonadGen m => Set a -> m (Set a)
#

Generates a random subset of a set.

This shrinks towards the empty set.

valueshuffle :: MonadGen m => [a] -> m [a]
#

Generates a random permutation of a list.

This shrinks towards the order of the list being identical to the input list.

valueshuffleSeq :: MonadGen m => Seq a -> m (Seq a)
#

Generates a random permutation of a sequence.

This shrinks towards the order of the sequence being identical to the input sequence.

Sampling Generators

6 declarations
valuesample :: (HasCallStack, MonadIO m) => Gen a -> m a
#

Generate a sample from a generator.

This function is useful for examining a Gen in GHCi or other contexts. It is not appropriate for use in a test suite directly. You will only get a single sample from this function, and it will not give you a property test. The seed is random, so the test is not deterministic.

If you only want a single test to run, then use withTests 1:

prop_OnlyRunOnce :: Property
prop_OnlyRunOnce =
  withTests 1 $ property $ do
    i <- Gen.int
    i /== 0
valueprint :: (MonadIO m, Show a) => Gen a -> m ()
#

Run a generator with a random seed and print the outcome, and the first level of shrinks.

Gen.print (Gen.enum 'a' 'f')
=== Outcome ===
'd'
=== Shrinks ===
'a'
'b'
'c'
valueprintTree :: (MonadIO m, Show a) => Gen a -> m ()
#

Run a generator with a random seed and print the resulting shrink tree.

Gen.printTree (Gen.enum 'a' 'f')
'd'
 ├╼'a'
 ├╼'b'
 │  └╼'a'
 └╼'c'
    ├╼'a'
    └╼'b'
       └╼'a'

This may not terminate when the tree is very large.

valueprintWith :: (MonadIO m, Show a) => Size -> Seed -> Gen a -> m ()
#

Print the value produced by a generator, and the first level of shrinks, for the given size and seed.

Use print to generate a value from a random seed.

Internal

0 declarations

These functions are exported in case you need them in a pinch, but are not part of the public API and may change at any time, even as part of a minor update.

Transfomer

valuefromTree :: MonadGen m => Tree a -> m a
#

Lift a predefined shrink tree in to a generator, ignoring the seed and the size.

Size

valuegolden :: Size -> Size
#

Scale a size using the golden ratio.

golden x = x / φ
golden x = x / 1.61803..

Shrinking

valueatLeast :: Int -> [a] -> Bool
#

Check that list contains at least a certain number of elements.

Characters

Subterms

datadata Vec (n :: Nat) a where
#

Constructors

Instances3Functor, Foldable, Traversable
  • Functor (Vec n)Defined in hedgehog-1.7 · Hedgehog.Internal.Gen
  • Foldable (Vec n)Defined in hedgehog-1.7 · Hedgehog.Internal.Gen
  • Traversable (Vec n)Defined in hedgehog-1.7 · Hedgehog.Internal.Gen
valuesubtermMVec :: MonadGen m => Vec n (m a) -> (Vec n a -> m a) -> m a
#

Constructs a generator from a number of sub-term generators.

Shrinks to one of the sub-terms if possible.