| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Hedgehog.Function
Contents
Description
The general procedure for generating functions of type A -> B looks something like this:
{-# language DeriveGeneric #-}
{-# language TypeApplications #-}
import Hedgehog
import Hedgehog.Function
data A = ...
deriving (Generic, ...)
instance Arg A
instance Vary A
genB :: MonadGen m => m B
genB = ...
prop_test :: Property
prop_test =
property $ do
f <- forAllFn $ fn @A genB
...
Here's an example of how to use the library to test the "fmap composition" law.
ScopedTypeVariables and TypeApplications are recommended for ease of use. RankNTypes
is only necessary for this example.
{-# language RankNTypes #-}
{-# language ScopedTypeVariables, TypeApplications #-}
import Hedgehog
import Hedgehog.Function
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
map_compose
:: forall f a b c
. ( Functor f
, Show (f a)
, Show a, Arg a, Vary a
, Show b, Arg b, Vary b
, Show c
, Eq (f c)
, Show (f c)
)
=> (forall x. Gen x -> Gen (f x))
-> Gen a
-> Gen b
-> Gen c
-> Property
map_compose genF genA genB genC =
property $ do
g <- forAllFn $ fn @a genB
f <- forAllFn $ fn @b genC
xs <- forAll $ genF genA
fmap (f . g) xs === fmap f (fmap g xs)
prop_map_list :: Property
prop_map_list =
map_compose
(Gen.list (Range.constant 0 100))
Gen.bool
Gen.bool
Gen.bool
Synopsis
- module GHC.Generics
- data Fn a b
- forAllFn :: (Show a, Show b, Monad m) => Gen (Fn a b) -> PropertyT m (a -> b)
- apply :: Fn a b -> a -> b
- fn :: (Arg a, Vary a) => Gen b -> Gen (Fn a b)
- fnWith :: Arg a => CoGen a -> Gen b -> Gen (Fn a b)
- gbuild :: (Generic a, GArg (Rep a)) => (a -> c) -> a :-> c
- via :: Arg b => (a -> b) -> (b -> a) -> (a -> c) -> a :-> c
- buildIntegral :: (Arg a, Integral a) => (a -> c) -> a :-> c
- class Arg a where
- module Data.Functor.Contravariant
- module Data.Functor.Contravariant.Divisible
- data CoGenT m a
- type CoGen = CoGenT Identity
- gvary :: (Generic a, GVary (Rep a)) => CoGenT m a
- varyIntegral :: Integral a => CoGenT m a
- class Vary a where
Documentation
module GHC.Generics
The type of randomly-generated functions
Generation
forAllFn :: (Show a, Show b, Monad m) => Gen (Fn a b) -> PropertyT m (a -> b) Source #
Run the function generator to retrieve a function
fnWith :: Arg a => CoGen a -> Gen b -> Gen (Fn a b) Source #
Generate a function using the user-supplied co-generator
Building
gbuild :: (Generic a, GArg (Rep a)) => (a -> c) -> a :-> c Source #
Reify a function whose domain has an instance of Generic
via :: Arg b => (a -> b) -> (b -> a) -> (a -> c) -> a :-> c Source #
Reify a function via an isomorphism.
If your function's domain has no instance of Generic then you can still reify it using
an isomorphism to a better domain type. For example, the Arg instance for Integral
uses an isomorphism from Integral a => a to (Bool, [Bool]), where the first element
is the sign, and the second element is the bit-string.
Note: via f g will only be well-behaved if g . f = id and f . g = id
instance Arg A where allows functions which take As to be reified
Minimal complete definition
Nothing
Methods
build :: (a -> c) -> a :-> c Source #
build :: (Generic a, GArg (Rep a)) => (a -> c) -> a :-> c Source #
Instances
| Arg Bool Source # | |
| Arg Int Source # | |
| Arg Int8 Source # | |
| Arg Int16 Source # | |
| Arg Int32 Source # | |
| Arg Int64 Source # | |
| Arg Integer Source # | |
| Arg Ordering Source # | |
| Arg () Source # | |
Defined in Hedgehog.Function.Internal | |
| Arg Void Source # | |
| Arg a => Arg [a] Source # | |
Defined in Hedgehog.Function.Internal | |
| Arg a => Arg (Maybe a) Source # | |
| (Arg a, Arg b) => Arg (Either a b) Source # | |
| (Arg a, Arg b) => Arg (a, b) Source # | |
Defined in Hedgehog.Function.Internal | |
Varying
module Data.Functor.Contravariant
A is used to perturb a CoGenT m a based on the value of the GenT m ba. This way,
the generated function will have a varying (but still deterministic) right hand side.
Co-generators can be built using Divisible and Decidable, but it is recommended to
derive Generic and use the default instance of the Vary type class.
CoGenTm ~Op(Endo(GenTm b))
gvary :: (Generic a, GVary (Rep a)) => CoGenT m a Source #
Build a co-generator for a type which has a Generic instance
Vary provides a canonical co-generator for a type.
While technically there are many possible co-generators for a given type, we don't get any benefit from caring.
Minimal complete definition
Nothing
Instances
| Vary Bool Source # | |
| Vary Int Source # | |
| Vary Int8 Source # | |
| Vary Int16 Source # | |
| Vary Int32 Source # | |
| Vary Int64 Source # | |
| Vary Integer Source # | |
| Vary Ordering Source # | |
| Vary Word8 Source # | |
| Vary () Source # | |
Defined in Hedgehog.Function.Internal | |
| Vary Void Source # | |
| Vary a => Vary [a] Source # | |
Defined in Hedgehog.Function.Internal | |
| Vary a => Vary (Maybe a) Source # | |
| (Vary a, Vary b) => Vary (Either a b) Source # | |
| (Vary a, Vary b) => Vary (a, b) Source # | |
Defined in Hedgehog.Function.Internal | |