test-fun-0.1.0.0: Testable functions

Safe HaskellSafe
LanguageHaskell2010

Test.Fun

Contents

Description

Testable representation of (higher-order) functions.

See the README for an introduction.

Synopsis

Testable functions

data a :-> r infixr 1 Source #

Testable representation of functions (a -> r).

This representation supports random generation, shrinking, and printing, for property testing with QuickCheck or Hedgehog.

Higher-order functions can be represented.

Instances
Functor ((:->) a) Source # 
Instance details

Defined in Test.Fun.Internal.Types

Methods

fmap :: (a0 -> b) -> (a :-> a0) -> a :-> b #

(<$) :: a0 -> (a :-> b) -> a :-> a0 #

Foldable ((:->) a) Source # 
Instance details

Defined in Test.Fun.Internal.Types

Methods

fold :: Monoid m => (a :-> m) -> m #

foldMap :: Monoid m => (a0 -> m) -> (a :-> a0) -> m #

foldr :: (a0 -> b -> b) -> b -> (a :-> a0) -> b #

foldr' :: (a0 -> b -> b) -> b -> (a :-> a0) -> b #

foldl :: (b -> a0 -> b) -> b -> (a :-> a0) -> b #

foldl' :: (b -> a0 -> b) -> b -> (a :-> a0) -> b #

foldr1 :: (a0 -> a0 -> a0) -> (a :-> a0) -> a0 #

foldl1 :: (a0 -> a0 -> a0) -> (a :-> a0) -> a0 #

toList :: (a :-> a0) -> [a0] #

null :: (a :-> a0) -> Bool #

length :: (a :-> a0) -> Int #

elem :: Eq a0 => a0 -> (a :-> a0) -> Bool #

maximum :: Ord a0 => (a :-> a0) -> a0 #

minimum :: Ord a0 => (a :-> a0) -> a0 #

sum :: Num a0 => (a :-> a0) -> a0 #

product :: Num a0 => (a :-> a0) -> a0 #

Traversable ((:->) a) Source # 
Instance details

Defined in Test.Fun.Internal.Types

Methods

traverse :: Applicative f => (a0 -> f b) -> (a :-> a0) -> f (a :-> b) #

sequenceA :: Applicative f => (a :-> f a0) -> f (a :-> a0) #

mapM :: Monad m => (a0 -> m b) -> (a :-> a0) -> m (a :-> b) #

sequence :: Monad m => (a :-> m a0) -> m (a :-> a0) #

Show r => Show (a :-> r) Source #

Pretty-printed Show instance.

Instance details

Defined in Test.Fun.Internal.Orphan

Methods

showsPrec :: Int -> (a :-> r) -> ShowS #

show :: (a :-> r) -> String #

showList :: [a :-> r] -> ShowS #

applyFun :: (a :-> r) -> a -> r Source #

Evaluate a representation into the function it represents.

applyFun2 :: (a :-> (b :-> r)) -> a -> b -> r Source #

Apply a binary function representation.

applyFun3 :: (a :-> (b :-> (c :-> r))) -> a -> b -> c -> r Source #

Apply a ternary function representation.

Shrink and show

shrinkFun :: forall a r. (r -> [r]) -> (a :-> r) -> [a :-> r] Source #

Simplify function.

showsPrecFun :: forall a r. ShowsPrec r -> ShowsPrec (a :-> r) Source #

Prettify function representation.

indent :: String -> String Source #

Break up lines after braces and indent.

Example

Expand

Input:

\x -> case x :: Either _ _ of { Left x1 -> case x1 of { Left x2 -> () ; Right x2 -> case x2 of {} } ; Right x1 -> () }

Output:

\x -> case x :: Either _ _ of {
  Left x1 -> case x1 of {
    Left x2 -> () ;
    Right x2 -> case x2 of {} } ;
  Right x1 -> () }

type ShowsPrec r = Int -> r -> String -> String Source #

The type of showsPrec.

Cogenerators

type Co gen a r = gen r -> gen (a :-> r) Source #

A "cogenerator" of a is a random generator of functions with domain a. They are parameterized by a generator in the codomain r.

More generally, we can make cogenerators to generate functions of arbitrary arities; Co gen a r is only the type of unary cogenerators.

gen r -> gen (a :-> r)         -- Co gen a r
gen r -> gen (a :-> b :-> r)
gen r -> gen (a :-> b :-> c :-> r)
gen r -> gen (a :-> b :-> c :-> d :-> r)

-- etc.

More details

Expand

Cogenerators can be composed using id and (.) (the usual combinators for functions). The arity of a cogenerator f . g is the sum of the arities of f and g.

id  ::  forall r. gen r -> gen r  -- 0-ary cogenerator

-- (1-ary) . (1-ary) = (2-ary)
(.) :: (forall r. gen r -> gen (a :-> r)) ->
       (forall r. gen r -> gen (b :-> r)) ->
       (forall r. gen r -> gen (a :-> b :-> r))

-- (2-ary) . (1-ary) = (3-ary)
(.) :: (forall r. gen r -> gen (a :-> b :-> r)) ->
       (forall r. gen r -> gen (c :-> r)) ->
       (forall r. gen r -> gen (a :-> b :-> c :-> r))

Note: the last type parameter r should really be universally quantified (as in the above pseudo type signatures), but instead we use more specialized types to avoid making types higher-ranked.

Main combinators

cogenEmbed :: Functor gen => FunName -> (a -> b) -> Co gen b r -> Co gen a r Source #

Cogenerator for a type a from a cogenerator for b, given an embedding function (a -> b), and a name for that function (used for pretty-printing).

Example

Expand

The common usage is to construct cogenerators for newtypes.

-- Given some cogenerator of Fruit
cogenFruit :: Co Gen Fruit r

-- Wrap Fruit in a newtype
newtype Apple = Apple { unApple :: Fruit }

cogenApple :: Co Gen Apple r
cogenApple = cogenEmbed "unApple" cogenFruit

If cogenFruit generates a function that looks like:

\y -> case y :: Fruit of { ... }

then cogenApple will look like this, where y is replaced with unApple x:

\x -> case unApple x :: Fruit of { ... }

cogenIntegral :: (Applicative gen, Integral a) => TypeName -> Co gen a r Source #

Cogenerator for an integral type. The name of the type is used for pretty-printing.

Example

Expand
cogenInteger :: Co Gen Integer r
cogenInteger = cogenIntegral "Integer"

cogenInt :: Co Gen Int r
cogenInt = cogenIntegral "Int"

cogenWord :: Co Gen Word r
cogenWord = cogenIntegral "Word"

cogenIntegral' :: Applicative gen => TypeName -> (a -> Integer) -> Co gen a r Source #

Variant of cogenIntegral with an explicit conversion to Integer.

cogenFun Source #

Arguments

:: Monad gen 
=> Concrete a0

Shrink and show a0.

-> gen (Maybe a0)

Generate representations of argument values.

-> (a0 -> a)

Interpret a representation a0 into a value a (id for simple data types).

-> Co gen b ((a -> b) :-> r)

Cogenerator of b.

-> Co gen (a -> b) r 

Construct a cogenerator of functions (a -> b) from a cogenerator of b, using gen (Maybe a0) to generate random arguments until it returns Nothing.

data Concrete r Source #

Dictionary with shrinker and printer. Used as part of the representation of higher-order functions with (:->).

Constructors

Concrete 

Fields

type FunName = String Source #

Name of a function.

type TypeName = String Source #

Name of a type.

Generic cogenerators

cogenGeneric :: forall a r gen. (Generic a, GCoGen a, Applicative gen) => GSumCo gen a r -> Co gen a r Source #

Cogenerator for generic types, parameterized by a list of cogenerators, one for each constructor.

The list is constructed with (:+) (pairs) and ().

Example

Expand
-- Cogenerator for lists, parameterized by a cogenerator for elements.
cogenList :: forall a. (forall r. Co Gen a r) -> (forall r. Co Gen [a] r)
cogenList coa = cogenGeneric gs where
  -- gs :: GSumCo Gen [a] r  -- unfolds to --
  gs ::
    (gen r -> gen r)                 :+  -- Cogenerator for the empty list
    (gen r -> gen (a :-> [a] :-> r)) :+  -- Cogenerator for non-empty lists
    ()
  gs = id :+ (coa . cogenList coa) :+ ()

data a :+ b infixr 2 Source #

Heterogeneous products as nested pairs. These products must be terminated by ().

a :+ b :+ c :+ ()  -- the product of a, b, c

Constructors

a :+ b infixr 2 

Secondary combinators

cogenList :: forall a r gen. Applicative gen => Co gen a ([a] :-> r) -> Co gen [a] r Source #

Cogenerator for lists.

Implementation note

Expand

The cogenerator of a is made monomorphic only to keep the type of cogenList at rank 1. But really, don't pay attention to the last type argument of Co.

cogenList :: ... => Co gen a _ -> Co gen [a] _

cogenConst :: Functor gen => Co gen a r Source #

The trivial cogenerator which generates a constant function.

cogenApply Source #

Arguments

:: Functor gen 
=> Concrete a0

Shrink and show a0.

-> (a0 -> a)

Reify to value a (id for simple data types).

-> a0

Value to inspect.

-> gen (b :-> ((a -> b) :-> r))

Cogenerator of b

-> gen ((a -> b) :-> r) 

Extend a cogenerator of functions (a -> b) (i.e., a generator of higher-order functions ((a -> b) -> r)), applying the function to a given value a and inspecting the result with a cogenerator of b.

This is parameterized by a way to generate, shrink, and show values of type a or, more generally, some representation a0 of values of type a.

Example

Expand
-- Assume Chips is some concrete type.
concreteChips :: Concrete Chips

-- Assume we have a cogenerator of Fish.
cogenFish :: forall r. Gen r -> Gen (Fish :-> r)

-- Then we can use cogenApply to construct this function
-- to transform cogenerators of functions (Chips -> Fish).
cogenX :: forall r.
  Chips ->
  Gen ((Chips -> Fish) :-> r) ->
  Gen ((Chips -> Fish) :-> r)
cogenX = cogenApply concreteChips id . cogenFish

-- If we have some inputs...
chips1, chips2, chips3 :: Chips

-- ... we can construct a cogenerator of functions by iterating cogenX.
cogenF :: forall r. Gen r -> Gen ((Chips -> Fish) :-> r)
cogenF = cogenX chips1 . cogenX chips2 . cogenX chips3 . cogenConst

CoArbitrary

class Applicative gen => CoArbitrary gen a where Source #

Implicit, default cogenerator.

Methods

coarbitrary :: forall r. Co gen a r Source #

Instances
Applicative gen => CoArbitrary gen Ordering Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen Ordering r Source #

Applicative gen => CoArbitrary gen Bool Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen Bool r Source #

Applicative gen => CoArbitrary gen Word Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen Word r Source #

Applicative gen => CoArbitrary gen Int Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen Int r Source #

Applicative gen => CoArbitrary gen Integer Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen Integer r Source #

Applicative gen => CoArbitrary gen Void Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen Void r Source #

Applicative gen => CoArbitrary gen () Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen () r Source #

CoArbitrary gen a => CoArbitrary gen (Sum a) Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen (Sum a) r Source #

CoArbitrary gen a => CoArbitrary gen (Identity a) Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen (Identity a) r Source #

CoArbitrary gen a => CoArbitrary gen (Maybe a) Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen (Maybe a) r Source #

CoArbitrary gen a => CoArbitrary gen [a] Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen [a] r Source #

(CoArbitrary gen a, CoArbitrary gen b) => CoArbitrary gen (Either a b) Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen (Either a b) r Source #

(CoArbitrary gen a, CoArbitrary gen b) => CoArbitrary gen (a, b) Source # 
Instance details

Defined in Test.Fun.Internal.Generic

Methods

coarbitrary :: Co gen (a, b) r Source #

coarbitraryGeneric :: forall a r gen. (Generic a, GCoArbitrary gen a) => Co gen a r Source #

Generic implementation of coarbitrary.

-- Assuming MyData is a data type whose fields are all instances of CoArbitrary.

instance CoArbitrary MyData where
  coarbitrary = coarbitraryGeneric

Generic classes

class (Typeable_ a, GNormalize (Rep a), GenBranches (Rep a)) => GCoGen a Source #

Class of types with generic cogenerators.

Instances
(Typeable_ a, GNormalize (Rep a), GenBranches (Rep a)) => GCoGen a Source # 
Instance details

Defined in Test.Fun.Internal.Generic

class (GCoGen a, Applicative gen, GSumCoArb gen (Rep a)) => GCoArbitrary gen a Source #

Constraint for coarbitraryGeneric.

Instances
(GCoGen a, Applicative gen, GSumCoArb gen (Rep a)) => GCoArbitrary gen a Source # 
Instance details

Defined in Test.Fun.Internal.Generic

type GSumCo gen a r = GSumCo_ gen (Rep a) r () Source #

The list of cogenerators for a generic type, one for each constructor.