-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | StrictCheck: Keep Your Laziness In Check -- -- StrictCheck is a property-based random testing framework for -- observing, specifying, and testing the strictness behaviors of Haskell -- functions. Strictness behavior is traditionally considered a -- non-functional property; StrictCheck allows it to be tested as if it -- were one, by reifying demands on data structures so they can be -- manipulated and examined within Haskell. @package StrictCheck @version 0.2.1 -- | This module defines a flexible and efficient way to curry and uncurry -- functions of any arity. This is useful in the context of StrictCheck -- to provide a lightweight interface to test developers which does not -- require them to directly work with heterogeneous lists. module Test.StrictCheck.Curry -- | Given a list of argument types and the "rest" of a function type, -- return a curried function type which takes the specified argument -- types in order, before returning the given rest -- -- For example: -- --
--   [Int, Bool] ⋯-> Char  ~  Int -> Bool -> Char
--   
-- -- This infix unicode symbol is meant to evoke a function arrow with an -- ellipsis. type family (args :: [*]) ⋯-> (rest :: *) :: * -- | For those who don't want to type in unicode, we provide this ASCII -- synonym for the ellipsis function arrow (⋯->) type args -..-> rest = args ⋯-> rest -- | Given a function type, return a list of all its argument types -- -- For example: -- --
--   Args (Int -> Bool -> Char)  ~  [Int, Bool]
--   
type family Args (f :: *) :: [*] -- | Strip all arguments from a function type, yielding its -- (non-function-type) result -- -- For example: -- --
--   Result (Int -> Bool -> Char)  ~  Char
--   
type family Result (f :: *) :: * -- | The Curry class witnesses that for any list of arguments, it is always -- possible to curry/uncurry at that arity class Curry (args :: [*]) uncurry :: forall result list. (Curry args, List list) => (args ⋯-> result) -> list args -> result curry :: forall result list. (Curry args, List list) => (list args -> result) -> args ⋯-> result -- | Curry all arguments to a function from a heterogeneous list to a -- result -- -- This is a special case of curry, and may ease type inference. curryAll :: forall args result list. (List list, Curry args) => (list args -> result) -> args ⋯-> result -- | Uncurry all arguments to a function type -- -- This is a special case of uncurry, and may ease type inference. uncurryAll :: forall function list. (List list, Curry (Args function)) => function -> list (Args function) -> Result function -- | For any function type function, it is always true that -- --
--   function  ~  (Args function ⋯-> Result function)
--   
-- -- GHC doesn't know this, however, so withCurryIdentity provides -- this proof to the enclosed computation, by discharging this wanted -- equality constraint. withCurryIdentity :: forall function r. (function ~ (Args function ⋯-> Result function) => r) -> r -- | This currying mechanism is agnostic to the concrete heterogeneous list -- type used to carry arguments. The List class abstracts over -- the nil and cons operations of a heterogeneous list: to use your own, -- just define an instance. class List (list :: [*] -> *) nil :: List list => list '[] cons :: List list => x -> list xs -> list (x : xs) uncons :: List list => list (x : xs) -> (x, list xs) instance Test.StrictCheck.Curry.Curry '[] instance Test.StrictCheck.Curry.Curry xs => Test.StrictCheck.Curry.Curry (x : xs) instance Test.StrictCheck.Curry.List (Generics.SOP.NP.NP Generics.SOP.BasicFunctors.I) -- | Internal module: This module does not make any stability -- guarantees, and may not adhere to the PVP. -- -- This module implements the rose-tree data structure used by -- StrictCheck to monomorphize inputs to functions. We decouple the -- consumption of input from the production of output by converting any -- input to an Input: a lazily constructed rose tree with nodes -- each containing a (Gen a -> Gen a) which captures a random -- perturbation associated with the shape of the value consumed. The -- tree-shape of an Input matches that of the entire consumed -- value, and evaluating any subpart of it forces the evaluation of the -- corresponding part of the original value. module Test.StrictCheck.Internal.Inputs -- | A variant which can be applied to any generator--kept in a newtype to -- get around lack of impredicativity. newtype Variant Variant :: (forall a. Gen a -> Gen a) -> Variant [vary] :: Variant -> forall a. Gen a -> Gen a -- | A tree representing all possible destruction sequences for a value -- Unfolding the contained lists forces a particular random control path -- for destructing the datatype. data Input -- | Not exposed in safe API Input :: Variant -> [Input] -> Input -- | A list of inputs given to a function, in abstract form. This lazy -- structure is evaluated piecewise during the course of producing a -- function, thus triggering the partial evaluation of the original input -- to the function. newtype Inputs -- | Not exposed in safe API Inputs :: [Input] -> Inputs -- | Extract the entropy and subfield-Inputs from a given -- Input draw :: Input -> (Variant, [Input]) -- | Extract the list of Inputs from an Inputs destruct :: Inputs -> [Input] instance GHC.Base.Semigroup Test.StrictCheck.Internal.Inputs.Variant instance GHC.Base.Monoid Test.StrictCheck.Internal.Inputs.Variant -- | This module defines the Consume typeclass, used for -- incrementally destructing inputs to random non-strict functions. -- -- Calling consume on some value lazily returns an abstract type -- of Input, which contains all the entropy present in the -- original value. Paired with Produce, these Input -- values can be used to generate random non-strict functions, whose -- strictness behavior is dependent on the values given to them. module Test.StrictCheck.Consume -- | A tree representing all possible destruction sequences for a value -- Unfolding the contained lists forces a particular random control path -- for destructing the datatype. data Input -- | A list of inputs given to a function, in abstract form. This lazy -- structure is evaluated piecewise during the course of producing a -- function, thus triggering the partial evaluation of the original input -- to the function. data Inputs -- | Lazily monomorphize some input value, by converting it into an -- Input. This is an incremental version of QuickCheck's -- CoArbitrary typeclass. It can also be seen as a -- generalization of the NFData class. -- -- Instances of Consume can be derived automatically for any -- type implementing the Generic class from GHC.Generics. -- Using the DeriveAnyClass extension, we can say: -- --
--   import GHC.Generics as GHC
--   import Generics.SOP as SOP
--   
--   data D x y
--     = A
--     | B (x, y)
--     deriving (GHC.Generic, SOP.Generic, Consume)
--   
-- -- This automatic derivation follows these rules, which you can follow -- too if you're manually writing an instance for some type which is not -- Generic: -- -- For each distinct constructor, make a single call to -- constructor with a distinct Int, and a list of -- Inputs, each created by recursively calling consume on -- every field in that constructor. For abstract types (e.g. sets), the -- same procedure can be used upon an extracted list representation of -- the contents. class Consume a -- | Convert an a into an Input by recursively -- destructing it using calls to consume consume :: Consume a => a -> Input -- | Convert an a into an Input by recursively -- destructing it using calls to consume consume :: (Consume a, GConsume a) => a -> Input -- | Reassemble pieces of input into a larger Input: this is to be called -- on the result of consume-ing subparts of input constructor :: Int -> [Input] -> Input -- | Fully normalize something which can be consumed normalize :: Consume a => a -> () -- | Consume a type which has no observable structure whatsoever -- -- This should only be used for types for which there is only one -- inhabitant, or for which inhabitants cannot be distinguished at all. consumeTrivial :: a -> Input -- | Use the CoArbitrary instance for a type to consume it -- -- This should only be used for "flat" types, i.e. those which contain no -- interesting consumable substructure, as it's fully strict -- (non-incremental) consumePrimitive :: CoArbitrary a => a -> Input -- | The constraints necessary to generically consume something type GConsume a = (Generic a, All2 Consume (Code a)) -- | Generic consume gConsume :: GConsume a => a -> Input instance Test.StrictCheck.Consume.Consume (a -> b) instance forall k (p :: k). Test.StrictCheck.Consume.Consume (Data.Proxy.Proxy p) instance Test.StrictCheck.Consume.Consume GHC.Types.Char instance Test.StrictCheck.Consume.Consume GHC.Types.Word instance Test.StrictCheck.Consume.Consume GHC.Types.Int instance Test.StrictCheck.Consume.Consume GHC.Types.Double instance Test.StrictCheck.Consume.Consume GHC.Types.Float instance Test.StrictCheck.Consume.Consume GHC.Real.Rational instance Test.StrictCheck.Consume.Consume GHC.Integer.Type.Integer instance (Test.QuickCheck.Arbitrary.CoArbitrary a, GHC.Float.RealFloat a) => Test.StrictCheck.Consume.Consume (Data.Complex.Complex a) instance Test.StrictCheck.Consume.Consume () instance Test.StrictCheck.Consume.Consume GHC.Types.Bool instance Test.StrictCheck.Consume.Consume GHC.Types.Ordering instance Test.StrictCheck.Consume.Consume a => Test.StrictCheck.Consume.Consume (GHC.Maybe.Maybe a) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b) => Test.StrictCheck.Consume.Consume (Data.Either.Either a b) instance Test.StrictCheck.Consume.Consume a => Test.StrictCheck.Consume.Consume [a] instance Test.StrictCheck.Consume.Consume a => Test.StrictCheck.Consume.Consume (GHC.Base.NonEmpty a) instance Test.StrictCheck.Consume.Consume a => Test.StrictCheck.Consume.Consume (Data.Tree.Tree a) instance Test.StrictCheck.Consume.Consume v => Test.StrictCheck.Consume.Consume (Data.Map.Internal.Map k v) instance Test.StrictCheck.Consume.Consume v => Test.StrictCheck.Consume.Consume (Data.Sequence.Internal.Seq v) instance Test.StrictCheck.Consume.Consume v => Test.StrictCheck.Consume.Consume (Data.Set.Internal.Set v) instance Test.StrictCheck.Consume.Consume v => Test.StrictCheck.Consume.Consume (Data.IntMap.Internal.IntMap v) instance Test.StrictCheck.Consume.Consume Data.IntSet.Internal.IntSet instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b) => Test.StrictCheck.Consume.Consume (a, b) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c) => Test.StrictCheck.Consume.Consume (a, b, c) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d) => Test.StrictCheck.Consume.Consume (a, b, c, d) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e) => Test.StrictCheck.Consume.Consume (a, b, c, d, e) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t, Test.StrictCheck.Consume.Consume u) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t, Test.StrictCheck.Consume.Consume u, Test.StrictCheck.Consume.Consume v) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t, Test.StrictCheck.Consume.Consume u, Test.StrictCheck.Consume.Consume v, Test.StrictCheck.Consume.Consume w) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t, Test.StrictCheck.Consume.Consume u, Test.StrictCheck.Consume.Consume v, Test.StrictCheck.Consume.Consume w, Test.StrictCheck.Consume.Consume x) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t, Test.StrictCheck.Consume.Consume u, Test.StrictCheck.Consume.Consume v, Test.StrictCheck.Consume.Consume w, Test.StrictCheck.Consume.Consume x, Test.StrictCheck.Consume.Consume y) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Consume.Consume b, Test.StrictCheck.Consume.Consume c, Test.StrictCheck.Consume.Consume d, Test.StrictCheck.Consume.Consume e, Test.StrictCheck.Consume.Consume f, Test.StrictCheck.Consume.Consume g, Test.StrictCheck.Consume.Consume h, Test.StrictCheck.Consume.Consume i, Test.StrictCheck.Consume.Consume j, Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume l, Test.StrictCheck.Consume.Consume m, Test.StrictCheck.Consume.Consume n, Test.StrictCheck.Consume.Consume o, Test.StrictCheck.Consume.Consume p, Test.StrictCheck.Consume.Consume q, Test.StrictCheck.Consume.Consume r, Test.StrictCheck.Consume.Consume s, Test.StrictCheck.Consume.Consume t, Test.StrictCheck.Consume.Consume u, Test.StrictCheck.Consume.Consume v, Test.StrictCheck.Consume.Consume w, Test.StrictCheck.Consume.Consume x, Test.StrictCheck.Consume.Consume y, Test.StrictCheck.Consume.Consume z) => Test.StrictCheck.Consume.Consume (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) -- | Internal module: This module does not make any stability -- guarantees, and may not adhere to the PVP. -- -- This module defines several utilities useful for shrinking demands and -- evaluations. -- -- Of these, only axialShrinks and fairInterleave are used -- by StrictCheck; nevertheless, we expose the DZipper type and -- its associated functions in this internal module just in case. module Test.StrictCheck.Internal.Shrink -- | Newtype allowing us to construct NP n-ary products of shrinkers newtype Shrink a Shrink :: (a -> [a]) -> Shrink a -- | Given a list of shrinkers and a list of values-to-be-shrunk, generate -- a list of shrunken lists-of-values, each inner list being one -- potential "axis" for shrinking -- -- That is, the first element of the result is all the ways the original -- product could be shrunken by only shrinking its first -- component, etc. axialShrinks :: SListI xs => NP Shrink xs -> NP I xs -> [[NP I xs]] -- | Fairly interleave a list of lists in a round-robin fashion fairInterleave :: [[a]] -> [a] -- | A DZipper is a suspended traversal through a non-empty -- NP n-ary product -- -- The position of the traversal within that product is existentially -- quantified. data DZipper f whole [DZipper] :: (NP f (c : rs) -> NP f whole) -> f c -> NP f rs -> DZipper f whole -- | Step one to the right in a DZipper, returning -- Nothing if this is not possible next :: DZipper f whole -> Maybe (DZipper f whole) -- | Given an n-ary product of xs, get a list of -- DZippers, each focused in sequence on the values of the input -- product -- -- This is similar to the duplicate operation on comonads. positions :: NP f xs -> [DZipper f xs] -- | Convert an n-ary product into a DZipper, returning -- Nothing if the input product is empty dzipper :: NP f xs -> Maybe (DZipper f xs) -- | Collapse a DZipper back into the n-ary product it represents dzip :: DZipper f xs -> NP f xs -- | Internal module: This module does not make any stability -- guarantees, and may not adhere to the PVP. -- -- This module defines the internal exception type used to implement the -- to/from-Demand methods in Test.StrictCheck.Demand. We don't -- export this type from the library to discourage users from interacting -- with this mechanism. module Test.StrictCheck.Internal.Unevaluated -- | In fromDemand, this exception is (purely, lazily) thrown -- whenever a Thunk is encountered. In toDemand, it is -- caught and converted back to a Thunk. data Unevaluated Unevaluated :: Unevaluated instance GHC.Show.Show Test.StrictCheck.Internal.Unevaluated.Unevaluated instance GHC.Exception.Type.Exception Test.StrictCheck.Internal.Unevaluated.Unevaluated -- | This module defines the Produce typeclass, used for generating -- random values for testing in StrictCheck. -- -- Produce is a strict generalization of Test.QuickCheck's -- Arbitrary typeclass. Paired with Consume (a -- generalization of CoArbitrary) it can be used to create random -- non-strict functions, whose strictness behavior is dependent on the -- values given to them. module Test.StrictCheck.Produce -- | Produce an arbitrary value of type b, such that destructing -- that value incrementally evaluates some input to a function. -- -- Writing instances of Produce is very similar to writing -- instances of QuickCheck's Arbitrary. The distinction: when -- making a recursive call to produce a subfield of a structure, -- always use build or recur, and never a -- direct call to produce itself. This ensures that the input can -- potentially be demanded at any step of evaluation of the produced -- value. -- -- If, in the course of generating a value of type b, you need -- to generate a random value of some other type, which is not -- going to be a subpart of the resultant b (e.g. a length or -- depth), use a direct call to arbitrary or some other -- generator which does not consume input. -- -- An example instance of Produce: -- --
--   data D a
--     = X a
--     | Y [Int]
--   
--   instance Produce a => Produce (D a) where
--     produce =
--       oneof [ fmap X recur
--             , fmap Y recur
--             ]
--   
class Produce b produce :: (Produce b, ?inputs :: Inputs) => Gen b -- | Destruct some inputs to generate an output. This function handles the -- interleaving of input destruction with output construction. When -- producing a data type, it should be called to produce each subfield -- -- *not* produce itself. recur :: (Produce a, ?inputs :: Inputs) => Gen a -- | Given an input-consuming producer, wrap it in an outer layer of input -- consumption, so that this consumption can be interleaved when the -- producer is called recursively to generate a subfield of a larger -- produced datatype. build :: ?inputs :: Inputs => (?inputs :: Inputs => Gen a) -> Gen a -- | Create an input-consuming producer of input-consuming functions, given -- an input-consuming producer for results of that function. returning :: (Consume a, ?inputs :: Inputs) => (?inputs :: Inputs => Gen b) -> Gen (a -> b) -- | Create an input-consuming producer of input-consuming functions, of -- any arity. This will usually be used in conjuntion with type -- application, to specify the type(s) of the argument(s) to the -- function. variadic :: forall args result. (All Consume args, Curry args, ?inputs :: Inputs) => (?inputs :: Inputs => Gen result) -> Gen (args ⋯-> result) -- | We hook into QuickCheck's existing Arbitrary infrastructure by using a -- newtype to differentiate our special way of generating things. newtype Lazy a Lazy :: a -> Lazy a [runLazy] :: Lazy a -> a -- | Actually produce an output, given an input-consuming producer. If a -- function is to be produced, it will be almost-certainly non-strict. freely :: (?inputs :: Inputs => Gen a) -> Gen a -- | A tree representing all possible destruction sequences for a value -- Unfolding the contained lists forces a particular random control path -- for destructing the datatype. data Input -- | A list of inputs given to a function, in abstract form. This lazy -- structure is evaluated piecewise during the course of producing a -- function, thus triggering the partial evaluation of the original input -- to the function. data Inputs -- | Destruct a random subpart of the given Inputs, returning the -- Variant corresponding to the combined information harvested -- during this process, and the remaining "leaves" of the inputs yet to -- be destructed -- -- To maximize the likelihood that different random consumption paths -- through the same value will diverge (desirable when generating -- functions with interesting strictness), draws destructs the -- forest of Inputs as a depth-first random traversal with a -- budget sampled from a geometric distribution with expectation 1. draws :: [Input] -> Gen (Variant, [Input]) instance Test.StrictCheck.Produce.Produce a => Test.QuickCheck.Arbitrary.Arbitrary (Test.StrictCheck.Produce.Lazy a) instance (Test.StrictCheck.Consume.Consume a, Test.StrictCheck.Produce.Produce b) => Test.StrictCheck.Produce.Produce (a -> b) instance Test.StrictCheck.Produce.Produce () instance Test.StrictCheck.Produce.Produce GHC.Types.Bool instance Test.StrictCheck.Produce.Produce GHC.Types.Ordering instance Test.StrictCheck.Produce.Produce GHC.Types.Char instance Test.StrictCheck.Produce.Produce GHC.Types.Word instance Test.StrictCheck.Produce.Produce GHC.Types.Int instance Test.StrictCheck.Produce.Produce GHC.Types.Double instance Test.StrictCheck.Produce.Produce GHC.Types.Float instance Test.StrictCheck.Produce.Produce GHC.Real.Rational instance Test.StrictCheck.Produce.Produce GHC.Integer.Type.Integer instance (Test.QuickCheck.Arbitrary.Arbitrary a, GHC.Float.RealFloat a) => Test.StrictCheck.Produce.Produce (Data.Complex.Complex a) instance Test.StrictCheck.Produce.Produce a => Test.StrictCheck.Produce.Produce (GHC.Maybe.Maybe a) instance (Test.StrictCheck.Produce.Produce a, Test.StrictCheck.Produce.Produce b) => Test.StrictCheck.Produce.Produce (Data.Either.Either a b) instance Test.StrictCheck.Produce.Produce a => Test.StrictCheck.Produce.Produce [a] -- | The match function in the typeclass Shaped allows you -- to uniformly operate over all the fields in a given piece of data--for -- instance, consuming them, iterating over them, counting them, etc. -- This module defines a uniform representation to allow this to work. -- -- This is in the nitty-gritty of how StrictCheck works: you do not need -- to understand this in order to use StrictCheck, unless you need to -- declare custom instances of Shaped for a type not supported -- by StrictCheck's generics mechanism (i.e. GADTs, existential types, -- abstract types). module Test.StrictCheck.Shaped.Flattened -- | The Flattened type contains all the fields in a piece of data -- (represented as an n-ary product NP from Generics.SOP), -- paired with a way to re-assemble them into a value of the original -- datatype. -- -- Flattened d f xs can be read as "some value of type d -- f, which has been separated into an n-ary product NP f -- xs and a function which can reconstruct a value d h for -- any h, given an n-ary product with matching field types to -- the one contained here. -- -- Pay attention to the kinds! d :: (* -> *) -> *, f -- :: * -> *, and xs :: [*]. -- -- For types which are literally a collection of fields with no extra -- information, the reconstruction function merely converts the given -- list of fields back into a value of the original type. For types which -- contain extra information in their values (beyond what StrictCheck -- considers fields), this function should contain that information, and -- re-attach it to the field values it receives. data Flattened d f xs [Flattened] :: (forall h. NP h xs -> d h) -> NP f xs -> Flattened d f xs -- | Use the re-assembly close in a Flattened to yield a value of -- the original type from which it was derived. unflatten :: Flattened d f xs -> d f -- | If all the fields in a Flattened satisfy some constraint, map -- a function expecting that constraint across all the fields. This may -- change the functor over which the Flattened value is -- parameterized. mapFlattened :: forall c d f g xs. All c xs => (forall x. c x => f x -> g x) -> Flattened d f xs -> Flattened d g xs -- | traverseFlattened is to traverse like -- mapFlattened is to fmap. traverseFlattened :: forall c d f g h xs. (All c xs, Applicative h) => (forall x. c x => f x -> h (g x)) -> Flattened d f xs -> h (Flattened d g xs) -- | This module defines the Shaped typeclass, which is used to -- generically manipulate values as fixed-points of higher-order functors -- in order to analyze their structure, e.g. while observing evaluation. -- -- If you just care about testing the strictness of functions over -- datatypes which are already instances of Shaped, you don't -- need to use this module. -- -- Important note: To define new instances of Shaped for -- types which implement Generic, an empty instance will -- suffice, as all the methods of Shaped can be filled in by -- generic implementations. For example: -- --
--   import GHC.Generics as GHC
--   import Generics.SOP as SOP
--   
--   data D = C deriving (GHC.Generic)
--   
--   instance SOP.Generic D
--   instance SOP.HasDatatypeInfo D
--   
--   instance Shaped D
--   
-- -- Using the DeriveAnyClass extension, this can be shortened to -- one line: -- --
--   data D = C deriving (GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo, Shaped)
--   
-- -- Manual instances of Shaped are necessary for types which do not -- or cannot implement GHC's Generic typeclass, such as -- existential types, abstract types, and GADTs. -- -- This module is heavily based upon the approach in -- Data.Functor.Foldable, which in turn is modeled after the paper -- "Functional Programming with Bananas, Lenses, Envelopes and Barbed -- Wire" (1991) by Erik Meijer, Maarten Fokkinga and Ross Paterson. If -- you don't yet understand recursion schemes and want to understand this -- module, it's probably a good idea to familiarize yourself with -- Data.Functor.Foldable before diving into this higher-order -- generalization. module Test.StrictCheck.Shaped -- | When a type a is Shaped, we know how to convert it -- into a representation parameterized by an arbitrary functor -- f, so that Shape a f (the "shape of a -- parameterized by f") is structurally identical to the topmost -- structure of a, but with f wrapped around any -- subfields of a. -- -- Note that this is not a recursive representation! The functor -- f in question wraps the original type of the field and -- not a Shape of that field. -- -- For instance, the Shape of Either a b might be: -- --
--   data EitherShape a b f
--     = LeftShape  (f a)
--     | RightShape (f b)
--   
--   instance Shaped (Either a b) where
--     type Shape (Either a b) = EitherShape a b
--     ...
--   
-- -- The shape of a primitive type should be isomorphic to the primitive -- type, with the functor parameter left unused. class Typeable a => Shaped (a :: *) where { -- | The Shape of an a is a type isomorphic to the -- outermost level of structure in an a, parameterized by the -- functor f, which is wrapped around any fields (of any type) -- in the original a. type family Shape a :: (* -> *) -> *; type Shape a = GShape a; } -- | Given a function to expand any Shaped x into an -- f x, expand an a into a Shape a f -- -- That is: convert the top-most level of structure in the given -- a into a Shape, calling the provided function on -- each field in the a to produce the f x necessary to -- fill that hole in the produced Shape a f. -- -- Inverse to embed. project :: Shaped a => (forall x. Shaped x => x -> f x) -> a -> Shape a f -- | Given a function to expand any Shaped x into an -- f x, expand an a into a Shape a f -- -- That is: convert the top-most level of structure in the given -- a into a Shape, calling the provided function on -- each field in the a to produce the f x necessary to -- fill that hole in the produced Shape a f. -- -- Inverse to embed. project :: (Shaped a, GShaped a) => (forall x. Shaped x => x -> f x) -> a -> Shape a f -- | Given a function to collapse any f x into a Shaped -- x, collapse a Shape a f into merely an a -- -- That is: eliminate the top-most Shape by calling the provided -- function on each field in that Shape a f, and using the -- results to fill in the pieces necessary to build an a. -- -- Inverse to project. embed :: Shaped a => (forall x. Shaped x => f x -> x) -> Shape a f -> a -- | Given a function to collapse any f x into a Shaped -- x, collapse a Shape a f into merely an a -- -- That is: eliminate the top-most Shape by calling the provided -- function on each field in that Shape a f, and using the -- results to fill in the pieces necessary to build an a. -- -- Inverse to project. embed :: (Shaped a, GShaped a) => (forall x. Shaped x => f x -> x) -> Shape a f -> a -- | Given two Shapes of the same type a but -- parameterized by potentially different functors f and -- g, pattern-match on them to expose a uniform view on their -- fields (a Flattened (Shape a)) to a continuation which -- may operate on those fields to produce some result -- -- If the two supplied Shapes do not structurally match, only -- the fields of the first are given to the continuation. If they do -- match, the fields of the second are also given, along with type-level -- proof that the types of the two sets of fields align. -- -- This very general operation subsumes equality testing, mapping, -- zipping, shrinking, and many other structural operations over -- Shaped things. -- -- It is somewhat difficult to manually write instances for this method, -- but consulting its generic implementation gMatch may prove -- helpful. -- -- See Test.StrictCheck.Shaped.Flattened for more information. match :: Shaped a => Shape a f -> Shape a g -> (forall xs. All Shaped xs => Flattened (Shape a) f xs -> Maybe (Flattened (Shape a) g xs) -> result) -> result -- | Given two Shapes of the same type a but -- parameterized by potentially different functors f and -- g, pattern-match on them to expose a uniform view on their -- fields (a Flattened (Shape a)) to a continuation which -- may operate on those fields to produce some result -- -- If the two supplied Shapes do not structurally match, only -- the fields of the first are given to the continuation. If they do -- match, the fields of the second are also given, along with type-level -- proof that the types of the two sets of fields align. -- -- This very general operation subsumes equality testing, mapping, -- zipping, shrinking, and many other structural operations over -- Shaped things. -- -- It is somewhat difficult to manually write instances for this method, -- but consulting its generic implementation gMatch may prove -- helpful. -- -- See Test.StrictCheck.Shaped.Flattened for more information. match :: (Shaped a, GShaped a) => Shape a f -> Shape a g -> (forall xs. All Shaped xs => Flattened (Shape a) f xs -> Maybe (Flattened (Shape a) g xs) -> result) -> result -- | Convert a Shape a whose fields are some unknown constant type -- into a RenderLevel filled with that type -- -- This is a specialized pretty-printing mechanism which allows for -- displaying counterexamples in a structured format. See the -- documentation for RenderLevel. render :: Shaped a => Shape a (K x) -> RenderLevel x -- | Convert a Shape a whose fields are some unknown constant type -- into a RenderLevel filled with that type -- -- This is a specialized pretty-printing mechanism which allows for -- displaying counterexamples in a structured format. See the -- documentation for RenderLevel. render :: (Shaped a, GShaped a, HasDatatypeInfo a) => Shape a (K x) -> RenderLevel x -- | A value of type f % a has the same structure as an -- a, but with the structure of the functor f -- interleaved at every field (including ones of types other than -- a). Read this type aloud as "a interleaved with f's". newtype (f :: * -> *) % (a :: *) :: * [Wrap] :: f (Shape a ((%) f)) -> f % a -- | Look inside a single level of an interleaved f % a. Inverse -- to the Wrap constructor. unwrap :: (f % a) -> f (Shape a ((%) f)) -- | Interleave an f-structure at every recursive level of some -- a, given some way of generating a single level of structure -- x -> f x. -- -- This is a special case of unfold. interleave :: (Functor f, Shaped a) => (forall x. x -> f x) -> a -> f % a -- | An infix synonym for interleave (%) :: forall a f. (Functor f, Shaped a) => (forall x. x -> f x) -> a -> f % a -- | Fuse the interleaved f-structure out of a recursively -- interleaved f % a, given some way of fusing a single level -- f x -> x. -- -- This is a special case of fold. fuse :: (Functor f, Shaped a) => (forall x. f x -> x) -> (f % a) -> a -- | Map a function across all the fields in a Shape -- -- This function may change the functor over which the Shape is -- parameterized. It can assume recursively that all the fields in the -- Shape are themselves instances of Shaped (which they -- should be!). This means that you can nest calls to translate -- recursively. translate :: forall a f g. Shaped a => (forall x. Shaped x => f x -> g x) -> Shape a f -> Shape a g -- | The equivalent of a fold (catamorphism) over recursively Shaped -- values -- -- Given a function which folds an f containing some Shape x -- g into a g x, recursively fold any interleaved f % -- a into a g a. fold :: forall a f g. (Functor f, Shaped a) => (forall x. Shaped x => f (Shape x g) -> g x) -> (f % a) -> g a -- | The equivalent of an unfold (anamorphism) over recursively -- Shaped values -- -- Given a function which unfolds an f x into a g -- containing some Shape x f, corecursively unfold any f -- a into an interleaved g % a. unfold :: forall a f g. (Functor g, Shaped a) => (forall x. Shaped x => f x -> g (Shape x f)) -> f a -> g % a -- | A higher-kinded unzipWith, operating over interleaved -- structures -- -- Given a function splitting some f x into a functor-product -- Product g h x, recursively split an interleaved f % -- a into two interleaved structures: one built of g-shapes -- and one of h-shapes. -- -- Note that Product ((%) g) ((%) h) a is isomorphic to (g % -- a, h % a); to get the latter, pattern-match on the Pair -- constructor of Product. unzipWith :: (All Functor [f, g, h], Shaped a) => (forall x. f x -> (g x, h x)) -> (f % a) -> (g % a, h % a) -- | A QName is a qualified name -- -- Note: > type ModuleName = String > type DatatypeName = String type QName = (ModuleName, DatatypeName, String) -- | Rendered f is the fixed-point of f composed with -- RenderLevel: it alternates between f shapes and -- RenderLevels. Usually, f will be the identity -- functor I, but not always. data Rendered f RWrap :: f (RenderLevel (Rendered f)) -> Rendered f -- | RenderLevel is a functor whose outer shape contains all the -- information about how to pretty-format the outermost Shape of -- some value. We use parametricity to make it difficult to construct -- incorrect render methods, by asking the user merely to produce -- a single RenderLevel and stitching nested -- RenderLevels into complete Rendered trees. data RenderLevel x -- | A prefix constructor, and a list of its fields ConstructorD :: QName -> [x] -> RenderLevel x -- | An infix constructor, its associativity and fixity, and its two fields InfixD :: QName -> Associativity -> Fixity -> x -> x -> RenderLevel x -- | A record constructor, and a list of its field names paired with fields RecordD :: QName -> [(QName, x)] -> RenderLevel x -- | A custom pretty-printing representation (i.e. for abstract types), -- which records a fixity and a list of tokens of three varieties: 1) raw -- strings, 2) qualified strings (from some module), or 3) actual fields, -- annotated with their fixity CustomD :: Fixity -> [Either (Either String (ModuleName, String)) (Fixity, x)] -> RenderLevel x -- | TODO: document this strange function -- -- Convert an f % a into a structured pretty-printing -- representation, suitable for further display/processing renderfold :: forall a f. (Shaped a, Functor f) => (f % a) -> Rendered f -- | The Shape of a primitive type should be equivalent to the -- type itself. However, this does not have the right kind to be -- used as a Shape. -- -- The Prim newtype solves this problem. By defining the -- Shape of some primitive type p to be Prim -- p, you can use the methods projectPrim, -- embedPrim, matchPrim, and prettyPrim to -- completely fill in the definition of the Shaped class for a -- primitive type. -- -- Note: It is only appropriate to use this Shape -- representation when a type really is primitive, in that it contains no -- interesting substructure. If you use the Prim representation -- inappropriately, StrictCheck will not be able to inspect the richer -- structure of the type in question. newtype Prim (x :: *) (f :: * -> *) Prim :: x -> Prim -- | Get the wrapped x out of a Prim x f (inverse to the -- Prim constructor) unPrim :: Prim x f -> x -- | Generic implementation of project for any primitive type -- whose Shape is is represented as a Prim newtype projectPrim :: (forall x. Shaped x => x -> f x) -> a -> Prim a f -- | Generic implementation of embed for any primitive type whose -- Shape is is represented as a Prim newtype embedPrim :: (forall x. Shaped x => f x -> x) -> Prim a f -> a -- | Generic implementation of match for any primitive type whose -- Shape is is represented as a Prim newtype with an -- underlying Eq instance matchPrim :: Eq a => Prim a f -> Prim a g -> (forall xs. All Shaped xs => Flattened (Prim a) f xs -> Maybe (Flattened (Prim a) g xs) -> result) -> result -- | Helper for writing match instances for primitive types which -- don't have Eq instance -- -- This generates a Flattened appropriate for using in the -- implementation of match. For more documentation on how to use -- this, see the documentation of match. flatPrim :: a -> Flattened (Prim a) g '[] -- | Generic implementation of render for any primitive type whose -- Shape is is represented as a Prim newtype renderPrim :: Show a => Prim a (K x) -> RenderLevel x -- | Given some string, generate a custom pretty-printing -- representation which just shows the string renderConstant :: String -> RenderLevel x -- | The Shape of a spine-strict container (i.e. a Map or -- Set) is the same as a container of demands on its elements. -- However, this does not have the right kind to be used as a -- Shape. -- -- The Containing newtype solves this problem. By defining the -- Shape of some container (C a) to be (C -- Containing a), you can use the methods -- projectContainer and embedContainer to implement -- project and embed for your container type (although -- you will still need to manually define match and -- render). newtype Containing h a f Container :: h (f a) -> Containing h a f -- | Generic implementation of project for any container type -- whose Shape is represented as a Containing newtype projectContainer :: (Functor c, Shaped a) => (forall x. Shaped x => x -> f x) -> c a -> Containing c a f -- | Generic implementation of embed for any container type whose -- Shape is represented as a Containing newtype embedContainer :: (Functor c, Shaped a) => (forall x. Shaped x => f x -> x) -> Containing c a f -> c a -- | The collection of constraints necessary for a type to be given a -- generic implementation of the Shaped methods type GShaped a = (Generic a, Shape a ~ GShape a, All2 Shaped (Code a), SListI (Code a), All SListI (Code a)) -- | The Shape used for generic implementations of Shaped -- -- This wraps a sum-of-products representation from Generics.SOP. newtype GShape a f GS :: NS (NP f) (Code a) -> GShape a f -- | Generic project gProject :: GShaped a => (forall x. Shaped x => x -> f x) -> a -> Shape a f -- | Generic embed gEmbed :: GShaped a => (forall x. Shaped x => f x -> x) -> Shape a f -> a -- | Generic match gMatch :: forall a f g result. GShaped a => Shape a f -> Shape a g -> (forall xs. All Shaped xs => Flattened (Shape a) f xs -> Maybe (Flattened (Shape a) g xs) -> result) -> result -- | Generic render gRender :: forall a x. (HasDatatypeInfo a, GShaped a) => Shape a (K x) -> RenderLevel x instance GHC.Num.Num x => GHC.Num.Num (Test.StrictCheck.Shaped.Prim x f) instance GHC.Show.Show x => GHC.Show.Show (Test.StrictCheck.Shaped.Prim x f) instance GHC.Classes.Ord x => GHC.Classes.Ord (Test.StrictCheck.Shaped.Prim x f) instance GHC.Classes.Eq x => GHC.Classes.Eq (Test.StrictCheck.Shaped.Prim x f) instance forall k1 (h :: k1 -> *) k2 (a :: k2) (f :: k2 -> k1). GHC.Show.Show (h (f a)) => GHC.Show.Show (Test.StrictCheck.Shaped.Containing h a f) instance forall k1 (h :: k1 -> *) k2 (a :: k2) (f :: k2 -> k1). GHC.Classes.Ord (h (f a)) => GHC.Classes.Ord (Test.StrictCheck.Shaped.Containing h a f) instance forall k1 (h :: k1 -> *) k2 (a :: k2) (f :: k2 -> k1). GHC.Classes.Eq (h (f a)) => GHC.Classes.Eq (Test.StrictCheck.Shaped.Containing h a f) instance GHC.Base.Functor Test.StrictCheck.Shaped.RenderLevel instance GHC.Show.Show x => GHC.Show.Show (Test.StrictCheck.Shaped.RenderLevel x) instance GHC.Classes.Ord x => GHC.Classes.Ord (Test.StrictCheck.Shaped.RenderLevel x) instance GHC.Classes.Eq x => GHC.Classes.Eq (Test.StrictCheck.Shaped.RenderLevel x) instance Test.StrictCheck.Shaped.Shaped () instance Test.StrictCheck.Shaped.Shaped GHC.Types.Bool instance Test.StrictCheck.Shaped.Shaped GHC.Types.Ordering instance Test.StrictCheck.Shaped.Shaped a => Test.StrictCheck.Shaped.Shaped (GHC.Maybe.Maybe a) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b) => Test.StrictCheck.Shaped.Shaped (Data.Either.Either a b) instance Test.StrictCheck.Shaped.Shaped a => Test.StrictCheck.Shaped.Shaped [a] instance (Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b) => Test.StrictCheck.Shaped.Shaped (a -> b) instance Test.StrictCheck.Shaped.Shaped GHC.Types.Char instance Test.StrictCheck.Shaped.Shaped GHC.Types.Word instance Test.StrictCheck.Shaped.Shaped GHC.Types.Int instance Test.StrictCheck.Shaped.Shaped GHC.Types.Double instance Test.StrictCheck.Shaped.Shaped GHC.Types.Float instance Test.StrictCheck.Shaped.Shaped GHC.Real.Rational instance Test.StrictCheck.Shaped.Shaped GHC.Integer.Type.Integer instance (Data.Typeable.Internal.Typeable a, GHC.Classes.Eq a, GHC.Show.Show a) => Test.StrictCheck.Shaped.Shaped (Data.Complex.Complex a) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b) => Test.StrictCheck.Shaped.Shaped (a, b) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b, Test.StrictCheck.Shaped.Shaped c) => Test.StrictCheck.Shaped.Shaped (a, b, c) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b, Test.StrictCheck.Shaped.Shaped c, Test.StrictCheck.Shaped.Shaped d) => Test.StrictCheck.Shaped.Shaped (a, b, c, d) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b, Test.StrictCheck.Shaped.Shaped c, Test.StrictCheck.Shaped.Shaped d, Test.StrictCheck.Shaped.Shaped e) => Test.StrictCheck.Shaped.Shaped (a, b, c, d, e) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b, Test.StrictCheck.Shaped.Shaped c, Test.StrictCheck.Shaped.Shaped d, Test.StrictCheck.Shaped.Shaped e, Test.StrictCheck.Shaped.Shaped f) => Test.StrictCheck.Shaped.Shaped (a, b, c, d, e, f) instance (Test.StrictCheck.Shaped.Shaped a, Test.StrictCheck.Shaped.Shaped b, Test.StrictCheck.Shaped.Shaped c, Test.StrictCheck.Shaped.Shaped d, Test.StrictCheck.Shaped.Shaped e, Test.StrictCheck.Shaped.Shaped f, Test.StrictCheck.Shaped.Shaped g) => Test.StrictCheck.Shaped.Shaped (a, b, c, d, e, f, g) -- | Internal module: This module does not make any stability -- guarantees, and may not adhere to the PVP. -- -- This module defines the Omega type, which has only one -- inhabitant: the infinite chain of successors. Any function which -- consumes an Omega is functionally equivalent to any other; -- likewise for those which produce an Omega. However, they may -- have radically differing strictness behaviors. It is for this reason -- that we have use for this type in the course of random example -- generation. module Test.StrictCheck.Internal.Omega -- | The type with one inhabitant: the infinite chain of successors data Omega Succ :: Omega -> Omega -- | Evaluate n constructors of a given Omega value, -- returning unit forceOmega :: Int -> Omega -> () instance Test.StrictCheck.Shaped.Shaped Test.StrictCheck.Internal.Omega.Omega instance Generics.SOP.Universe.HasDatatypeInfo Test.StrictCheck.Internal.Omega.Omega instance Generics.SOP.Universe.Generic Test.StrictCheck.Internal.Omega.Omega instance GHC.Generics.Generic Test.StrictCheck.Internal.Omega.Omega instance Test.StrictCheck.Produce.Produce Test.StrictCheck.Internal.Omega.Omega -- | A Demand on some value of type T is shaped like a -- T, but possibly truncated, to represent partial evaluation. -- This module defines the type of demands, and functions to manipulate -- them for the purpose of constructing demand specifications. -- -- A demand for some type T can be represented one of two -- interconvertible ways: -- -- -- -- The explicit representation is useful for writing traversals and other -- such manipulations of demand values, while the implicit representation -- can prove convenient for writing demand specifications. The implicit -- representation is the default when writing specifications, but through -- the use of toDemand and fromDemand, either -- representation can be used wherever it is most appropriate. module Test.StrictCheck.Demand -- | A Thunk a is either an a or a Thunk -- -- When we interleave this type into the Shape of some type, we -- get the type of demands on that type. -- -- Thunk a is isomorphic to a (strict) Maybe a. data Thunk a Eval :: !a -> Thunk a Thunk :: Thunk a -- | A Demand on some type a is the same shape as that -- original a, but with possible Thunks interleaved -- into it type Demand = (%) Thunk -- | A PosDemand is a "strictly positive" demand, i.e. one where -- the topmost level of the demanded value has definitely been forced -- -- This is the one-level unwrapping of Demand, and is useful to -- express some invariants in specifications type PosDemand a = Shape a Demand -- | Pattern synonym to abbreviate demand manipulation: E a = Wrap -- (Eval a) pattern E :: Shape a Demand -> Demand a -- | Pattern synonym to abbreviate demand manipulation: T = Wrap -- Thunk pattern T :: Demand a -- | Evaluate some value of type a to the degree specified by the -- given demand -- -- If the demand and the value diverge (they pick a different side of a -- sum), evaluation will stop at this point. Usually, -- evaluateDemand is only called on demands which are known to -- be structurally-compatible with the accompanying value, although -- nothing really goes wrong if this is not true. evaluateDemand :: forall a. Shaped a => PosDemand a -> a -> () -- | Shrink a non-zero demand (analogous to QuickCheck's shrink) -- -- While QuickCheck's typical shrink instances reduce the size -- of a value by slicing off the top-most structure, -- shrinkDemand reduces the size of a demand by pruning it's -- deepest leaves. This ensures that all resultant shrunken -- demands are strict sub-demands of the original. shrinkDemand :: forall a. Shaped a => PosDemand a -> [PosDemand a] -- | Pretty-print a demand for display prettyDemand :: Shaped a => Demand a -> String -- | Print a demand to standard output -- --
--   printDemand = putStrLn . prettyDemand
--   
printDemand :: Shaped a => Demand a -> IO () -- | Determine if two demands are exactly equal -- -- This relies on the match method from the Shaped -- instance for the two demands, and does not require the underlying -- types to have Eq instances. However, this means that types -- whose match methods are more coarse than their equality will -- be compared differently by eqDemand. In particular, the -- demand representations of functions will all be compared to be equal. eqDemand :: forall a. Shaped a => Demand a -> Demand a -> Bool -- | A very general showsPrec style function for printing demands -- -- showPrettyFieldThunkS q t p r returns a function (String -- -> String) which appends its input to a pretty-printed -- representation of a demand. -- -- Specifically: * q is a boolean flag determining if names -- should be printed as qualified * t is a string which is to be -- printed when a thunk is encountered * p is the precedence -- context of this function call * r is the 'Rendered Thunk' -- representing some demand -- -- This is very general, but we expose it in its complexity just in case -- some person wants to build a different pretty-printer. -- -- The precedence-aware pretty-printing algorithm used here is adapted -- from a solution given by Brian Huffman on StackOverflow: -- https://stackoverflow.com/questions/27471937/43639618#43639618. showPrettyFieldThunkS :: Bool -> String -> Int -> Rendered Thunk -> String -> String -- | A bottom value (inhabiting all types) which StrictCheck interprets as -- an unevaluated subpart of a data structure -- --
--   toDemand thunk  ==  T
--   fromDemand T    ==  thunk
--   
thunk :: forall a. a -- | Tests if a particular value is an implicit thunk -- -- In order to work, this function evaluates its input to weak-head -- normal form; keep this in mind if you care about laziness. isThunk :: Shaped a => a -> Bool -- | Given an a whose substructures may contain thunks -- (i.e. an implicit demand representation), convert it to an explicit -- Demand -- -- Inverse to fromDemand. toDemand :: Shaped a => a -> Demand a -- | Given an explicit Demand for some type a, convert it -- to a value of type a, substituting a thunk for each -- T found in the explicit demand -- -- Inverse to toDemand. fromDemand :: Shaped a => Demand a -> a instance GHC.Generics.Generic (Test.StrictCheck.Demand.Thunk a) instance GHC.Base.Functor Test.StrictCheck.Demand.Thunk instance GHC.Show.Show a => GHC.Show.Show (Test.StrictCheck.Demand.Thunk a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Test.StrictCheck.Demand.Thunk a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Test.StrictCheck.Demand.Thunk a) instance Test.StrictCheck.Shaped.Shaped a => GHC.Show.Show (Test.StrictCheck.Demand.Demand a) instance Test.StrictCheck.Shaped.Shaped a => GHC.Classes.Eq (Test.StrictCheck.Demand.Demand a) instance GHC.Base.Applicative Test.StrictCheck.Demand.Thunk instance GHC.Num.Num a => GHC.Num.Num (Test.StrictCheck.Demand.Thunk a) -- | This module defines the underlying unsafe primitives -- StrictCheck uses to implement purely functional observation of -- evaluation. -- -- The "functions" in this module are not referentially -- transparent! module Test.StrictCheck.Observe.Unsafe -- | From some value of any type, produce a pair: a copy of the original -- value, and a Thunk of that same type, with their values -- determined by the order in which their values themselves are -- evaluated -- -- If the copy of the value is evaluated to weak-head normal form before -- the returned Thunk, then any future inspection of the -- Thunk will show that it is equal to the original value -- wrapped in an Eval. However, if the copy of the value is -- not evaluated by the time the Thunk is evaluated, any -- future inspection of the Thunk will show that it is equal to -- Thunk. -- -- A picture may be worth 1000 words: -- --
--   >>> x = "hello," ++ " world"
--   
--   >>> (x', t) = entangle x
--   
--   >>> x'
--   "hello, world"
--   
--   >>> t
--   Eval "hello, world"
--   
-- --
--   >>> x = "hello," ++ " world"
--   
--   >>> (x', t) = entangle x
--   
--   >>> t
--   Thunk
--   
--   >>> x'
--   "hello, world"
--   
--   >>> t
--   Thunk
--   
entangle :: forall a. a -> (a, Thunk a) -- | Recursively entangle an a, producing not merely a -- Thunk, but an entire Demand which is piecewise -- entangled with that value. Whatever portion of the entangled value is -- evaluated before the corresponding portion of the returned -- Demand will be represented in the shape of that -- Demand. However, any part of the returned Demand -- which is evaluated before the corresponding portion of the entangled -- value will be forever equal to Thunk. -- -- The behavior of this function is even more tricky to predict than that -- of entangle, especially when evaluation of the entangled value -- and the corresponding Demand happen at the same time. In -- StrictCheck, all evaluation of the entangled value occurs before any -- evaluation of the Demand; we never interleave their -- evaluation. instrument :: Shaped a => a -> (a, Demand a) -- | This module implements the core "trick" of StrictCheck: observing the -- demand behavior of a function in a purely functional way. -- -- All the functions in this module are safe and referentially -- transparent. -- -- Observing the evaluation of a function using these functions incurs at -- most a small constant multiple of overhead compared to just executing -- the function with no observation. module Test.StrictCheck.Observe -- | Observe the demand behavior -- -- -- -- returning a pair of -- -- -- -- Suppose we want to see how strict reverse is when we evaluate -- its result to weak-head normal form: -- --
--   >>> (b, a) = observe1 (`seq` ()) (reverse @Int) [1, 2, 3]
--   
--   >>> printDemand b  -- output demand
--   _ : _
--   
--   >>> printDemand a  -- input demand
--   _ : _ : _ : _ : []
--   
-- -- This tells us that our context did indeed evaluate the result of -- reverse to force only its first constructor, and that doing -- so required the entire spine of the list to be evaluated, but did not -- evaluate any of its elements. observe1 :: (Shaped a, Shaped b) => (b -> ()) -> (a -> b) -> a -> (Demand b, Demand a) -- | Observe the demand behavior -- -- -- -- returning a pair of -- -- -- -- This function is variadic and curried: it takes n + 2 -- arguments, where n is the total number of arguments taken by -- the observed function. -- -- Suppose we want to see how strict zipWith (*) is when we -- evaluate its result completely (to normal form): -- --
--   >>> productZip = zipWith ((*) @Int)
--   
--   >>> (zs, (xs :* ys :* Nil)) = observe normalize productZip [10, 20] [30, 40]
--   
--   >>> printDemand zs  -- output demand
--   300 : 800 : []
--   
--   >>> printDemand xs  -- input demand #1
--   10 : 20 : []
--   
--   >>> printDemand ys  -- input demand #2
--   30 : 40 : _
--   
-- -- If you haven't thought very carefully about the strictness behavior of -- zip, this may be a surprising result; this is part of the -- fun! observe :: (All Shaped (Args function), Shaped (Result function), Curry (Args function)) => (Result function -> ()) -> function -> Args function ⋯-> (Demand (Result function), NP Demand (Args function)) -- | Observe the demand behavior -- -- -- -- returning a pair of -- -- -- -- This is mostly useful for implementing the internals of StrictCheck; -- observe is more ergonomic for exploration by end-users. observeNP :: (All Shaped inputs, Shaped result) => (result -> ()) -> (NP I inputs -> result) -> NP I inputs -> (Demand result, NP Demand inputs) -- | The top-level interface to the StrictCheck library for random -- strictness testing. -- -- Quick Start: -- -- Want to explore the strictness of functions before you write -- specifications? Go to Test.StrictCheck.Observe and look at the -- functions observe1 and observe. -- -- Want to check the strictness of a function against a specification of -- its strictness? -- --
    --
  1. Write a Spec describing your expectation of the function's -- behavior. See Test.StrictCheck.Demand for more on working with -- demands, and Test.StrictCheck.Examples.Lists for examples of -- some specifications of functions on lists.
  2. --
  3. Check your function using strictCheckSpecExact, like -- so:
  4. --
-- --
--   strictCheckSpecExact spec function
--   
-- -- If your function passes testing, you'll get a success message just -- like in Test.QuickCheck; if a counterexample to your -- specification is found, you will see a pretty Unicode box diagram -- describing the mismatch. -- -- Hint: StrictCheck, just like QuickCheck, doesn't work with -- polymorphic functions. If you get baffling type errors, first make -- sure that all your types are totally concrete. module Test.StrictCheck -- | A demand specification for some function f is itself a -- function which manipulates demand values for some function's arguments -- and results -- -- A Spec for f wraps a function which takes, in order: -- -- -- -- The intention is that the Spec will call predict on -- some set of demands representing the demands it predicts that -- f will exert on its inputs, given the provided demand on -- f's outputs. -- -- For example, here is a correct Spec for take: -- --
--   take_spec :: Spec '[Int, [a]] [a]
--   take_spec =
--    Spec $ \predict d n xs ->
--      predict n (if n > length xs then d else d ++ thunk)
--   
-- -- See the documentation for Test.StrictCheck.Demand for -- information about how to manipulate these implicit demand -- representations when writing Specs, and see the documentation -- for Test.StrictCheck.Examples.Lists for more examples of -- writing specifications. newtype Spec (args :: [*]) (result :: *) Spec :: (forall r. (args ⋯-> r) -> result -> args ⋯-> r) -> Spec -- | Unwrap a Spec constructor, returning the contained CPS-ed -- specification -- -- Conceptually, this is the inverse to the Spec constructor, -- but because Spec is variadic, getSpec . Spec and -- Spec . getSpec don't typecheck without additional type -- annotation. getSpec :: forall r args result. Spec args result -> (args ⋯-> r) -> result -> args ⋯-> r -- | A function can be checked against a specification if it meets the -- StrictCheck constraint type StrictCheck function = (Shaped (Result function), Consume (Result function), Curry (Args function), All Typeable (Args function), All Shaped (Args function)) -- | Check a function to see whether it exactly meets a strictness -- specification -- -- If the function fails to meet the specification, a counterexample is -- pretty-printed in a box-drawn diagram illustrating how the -- specification failed to match the real observed behavior of the -- function. strictCheckSpecExact :: forall function. (StrictCheck function, All Arbitrary (Args function), All Produce (Args function)) => Spec (Args function) (Result function) -> function -> IO () -- | The most general function for random strictness testing: all of the -- more convenient such functions can be derived from this one -- -- Given some function f, this takes as arguments: -- -- -- -- If all tests succeed, (Nothing, result) is returned, where -- result is the underlying Result type from -- Test.QuickCheck. If there is a test failure, it also returns -- Just the failed Evaluation as well as whatever -- evidence was produced by the predicate. strictCheckWithResults :: forall function evidence. StrictCheck function => Args -> NP Shrink (Args function) -> NP Gen (Args function) -> Gen Strictness -> (Evaluation (Args function) (Result function) -> Maybe evidence) -> function -> IO (Maybe (Evaluation (Args function) (Result function), evidence), Result) -- | The default way to generate inputs: via Produce genViaProduce :: All Produce xs => NP Gen xs -- | Newtype allowing us to construct NP n-ary products of shrinkers newtype Shrink a Shrink :: (a -> [a]) -> Shrink a -- | The default way to shrink inputs: via shrink (from -- Test.QuickCheck's Arbitrary typeclass) shrinkViaArbitrary :: All Arbitrary xs => NP Shrink xs -- | A Strictness represents (roughly) how strict a randomly -- generated function or evaluation context should be -- -- An evaluation context generated with some strictness s (i.e. -- through evaluationForall) will consume at most s -- constructors of its input, although it might consume fewer. data Strictness -- | The default way to generate random strictnesses: uniformly choose -- between 1 and the test configuration's size parameter strictnessViaSized :: Gen Strictness -- | A snapshot of the observed strictness behavior of a function -- -- An Evaluation contains the inputs at which a function -- was called, the inputDemands which were induced upon those -- inputs, and the resultDemand which induced that demand on the -- inputs. data Evaluation args result Evaluation :: NP I args -> NP Demand args -> PosDemand result -> Evaluation args result -- | Inputs to a function [inputs] :: Evaluation args result -> NP I args -- | Demands on the input [inputDemands] :: Evaluation args result -> NP Demand args -- | Demand on the result [resultDemand] :: Evaluation args result -> PosDemand result -- | Given a list of generators for a function's arguments and a generator -- for random strictnesses (measured in number of constructors -- evaluated), create a generator for random Evaluations of that -- function in random contexts evaluationForall :: forall f. (Curry (Args f), Consume (Result f), Shaped (Result f), All Shaped (Args f)) => NP Gen (Args f) -> Gen Strictness -> f -> Gen (Evaluation (Args f) (Result f)) -- | Given a shrinker for each of the arguments of a function, the function -- itself, and some Evaluation of that function, produce a list of -- smaller Evaluations of that function shrinkEvalWith :: forall f. (Curry (Args f), Shaped (Result f), All Shaped (Args f)) => NP Shrink (Args f) -> f -> Evaluation (Args f) (Result f) -> [Evaluation (Args f) (Result f)] -- | A newtype for wrapping a comparison on demands -- -- This is useful when constructing an NP n-ary product of such -- comparisons. newtype DemandComparison a DemandComparison :: (Demand a -> Demand a -> Bool) -> DemandComparison a -- | Given a list of ways to compare demands, a demand specification, and -- an evaluation of a particular function, determine if the function met -- the specification, as decided by the comparisons. If so, return the -- prediction of the specification. compareToSpecWith :: forall args result. (All Shaped args, Curry args, Shaped result) => NP DemandComparison args -> Spec args result -> Evaluation args result -> Maybe (NP Demand args) -- | Checks if a given Evaluation exactly matches the prediction of -- a given Spec, returning the prediction of that Spec if -- not -- -- Note: In the case of success this returns -- Nothing; in the case of failure this returns -- Just the incorrect prediction. equalToSpec :: forall args result. (All Shaped args, Shaped result, Curry args) => Spec args result -> Evaluation args result -> Maybe (NP Demand args) -- | An n-ary product. -- -- The product is parameterized by a type constructor f and -- indexed by a type-level list xs. The length of the list -- determines the number of elements in the product, and if the -- i-th element of the list is of type x, then the -- i-th element of the product is of type f x. -- -- The constructor names are chosen to resemble the names of the list -- constructors. -- -- Two common instantiations of f are the identity functor -- I and the constant functor K. For I, the product -- becomes a heterogeneous list, where the type-level list describes the -- types of its components. For K a, the product becomes -- a homogeneous list, where the contents of the type-level list are -- ignored, but its length still specifies the number of elements. -- -- In the context of the SOP approach to generic programming, an n-ary -- product describes the structure of the arguments of a single data -- constructor. -- -- Examples: -- --
--   I 'x'    :* I True  :* Nil  ::  NP I       '[ Char, Bool ]
--   K 0      :* K 1     :* Nil  ::  NP (K Int) '[ Char, Bool ]
--   Just 'x' :* Nothing :* Nil  ::  NP Maybe   '[ Char, Bool ]
--   
data NP (a :: k -> Type) (b :: [k]) :: forall k. () => k -> Type -> [k] -> Type [Nil] :: forall k (a :: k -> Type) (b :: [k]). () => NP a ([] :: [k]) [:*] :: forall k (a :: k -> Type) (b :: [k]) (x :: k) (xs :: [k]). () => a x -> NP a xs -> NP a (x : xs) infixr 5 :* -- | The identity type functor. -- -- Like Identity, but with a shorter name. newtype I a I :: a -> I a -- | Require a constraint for every element of a list. -- -- If you have a datatype that is indexed over a type-level list, then -- you can use All to indicate that all elements of that -- type-level list must satisfy a given constraint. -- -- Example: The constraint -- --
--   All Eq '[ Int, Bool, Char ]
--   
-- -- is equivalent to the constraint -- --
--   (Eq Int, Eq Bool, Eq Char)
--   
-- -- Example: A type signature such as -- --
--   f :: All Eq xs => NP I xs -> ...
--   
-- -- means that f can assume that all elements of the n-ary -- product satisfy Eq. class (AllF f xs, SListI xs) => All (f :: k -> Constraint) (xs :: [k]) instance GHC.Num.Num Test.StrictCheck.Strictness instance GHC.Show.Show Test.StrictCheck.Strictness instance GHC.Classes.Ord Test.StrictCheck.Strictness instance GHC.Classes.Eq Test.StrictCheck.Strictness instance (Generics.SOP.Constraint.All Data.Typeable.Internal.Typeable args, Data.Typeable.Internal.Typeable result) => GHC.Show.Show (Test.StrictCheck.Evaluation args result) -- | This module defines a variety of specifications for functions on -- lists, demonstrating the specification interface of StrictCheck. See -- the documentation of Test.StrictCheck (specifically -- strictCheckSpecExact) for details on how to test these -- specifications. -- -- This module's primary utility is to teach how specifications work. -- Because Haddock omits the definitions of values, you'll learn the most -- by viewing the source of this module. module Test.StrictCheck.Examples.Lists -- | A correct specification for length length_spec :: Spec '[[a]] Int -- | A naive specification for take, which is wrong take_spec_too_easy :: Spec '[Int, [a]] [a] -- | A correct specification for take take_spec :: Spec '[Int, [a]] [a] -- | A functionally correct implementation of take which has subtly -- different strictness properties -- -- This will fail when tested against take_spec. take' :: Int -> [a] -> [a] -- | A correct specification of '(++)' append_spec :: Shaped a => Spec '[[a], [a]] [a] -- | A correct specification of reverse reverse_spec :: Shaped a => Spec '[[a]] [a] -- | A correct specification for zip zip_spec :: (Shaped a, Shaped b) => Spec '[[a], [b]] [(a, b)] -- | A functionally correct implementation of zip which has subtly -- different strictness properties -- -- This will fail when tested against zip_spec. zip' :: [a] -> [b] -> [(a, b)] -- | A correct specification for map, demonstrating specifications -- for higher-order functions map_spec :: forall a b. (Shaped a, Shaped b) => Spec '[a -> b, [a]] [b] -- | Given three lists xs, ys, and zs, compute -- xs ++ reverse ys ++ zs, but with more uniform strictness -- -- Specifically, if ys is shorter than xs, the work -- necessary to reverse it will have already occurred by the time -- xs is traversed. rotate :: [a] -> [a] -> [a] -> [a] -- | Specialization of rotate: rot xs ys = rotate xs ys [] rot :: [a] -> [a] -> [a] -- | The naive version of rot: rot' xs ys = xs ++ reverse -- ys -- -- This is functionally equivalent to rot but not equivalent in -- strictness behavior. rot' :: [a] -> [a] -> [a] -- | A previous iteration of rot_spec', this one is also correct, -- but may be less readable. rot_spec :: Shaped a => Spec '[[a], [a]] [a] -- | A correct specification of rot, this is also the version we -- presented in the paper. rot_spec' :: Shaped a => Spec '[[a], [a]] [a] -- | An incorrect specification for rot that miscalculates the -- number of cells forced. rot_simple_spec :: Shaped a => Spec '[[a], [a]] [a] test_rot :: [Int] -> [Int] -> [Int] -> IO () -- | If the tail of the second list is thunk, replace it with the -- first list replaceThunk :: Shaped a => [a] -> [a] -> [a] -- | If the tail of the list is thunk, replace it with [] -- -- This is a special case of replaceThunk. cap :: Shaped a => [a] -> [a] -- | Lift an ordinary function to apply to explicit Demands -- -- It is true that Demands are a functor, but they can't be a -- Haskell Functor because they're a type family (%$) :: (Shaped a, Shaped b) => (a -> b) -> Demand a -> Demand b -- | Apply a Demand on a function to a Demand on a value -- -- It is true that Demands are an applicative functor, but they -- can't be a Haskell Functor because they're a type family (%*) :: (Shaped a, Shaped b) => Demand (a -> b) -> Demand a -> Demand b -- | Given a unary function, an implicit demand on its result, and its -- input, compute its actual demand on its input in that context -- -- This demand is calculated using observe1, so it is guaranteed -- to be correct. specify1 :: forall a b. (Shaped a, Shaped b) => (a -> b) -> b -> a -> a -- | Given an implicit demand, convert it to an evaluation context -- -- That is, toContext d a evaluates a to the degree -- that d is a defined value. This uses the function -- evaluateDemand; refer to its documentation for details about -- how demands are used to evaluate values. toContext :: Shaped b => b -> b -> () -- | Assert at runtime that a value is not a thunk, failing -- with an error if it is expectTotal :: Shaped a => a -> a -- | Template Haskell to derive pattern synonyms for working with demands module Test.StrictCheck.TH -- | Template Haskell splice to generate pattern synonym declarations for -- working with explicitly-represented demands on a type whose -- Shape is implemented generically as a GShape derivePatternSynonyms :: Name -> Q [Dec] -- | This module showcases another type of specification different from -- those in Test.StrictCheck.Examples.Lists. Here, we demonstrate -- that StrictCheck is able to distinguish value-lazy maps from -- value-strict maps. -- -- In this module, we first develop the solution of the Knapsack dynamic -- programming problem by taking the fixpoint of a step function of the -- solution table. We represent the solution table with a map, and write -- a specification that is critical for the termination of this solution. module Test.StrictCheck.Examples.Map -- | We roll our own map type to avoid dealing with abstract types. data Map k v -- | A node that contains a key value pair Bin :: Map k v -> k -> v -> Map k v -> Map k v -- | An empty node Empty :: Map k v -- | A specialized map useful for knapsack. The pair of ints represent the -- two parameters to each knapsack sub-problem solved along the way. -- These two parameters determine the subsequence of items each -- sub-problem is concerned with, and the weight limit. type KMap = Map (Int, Int) Int pattern Empty' :: Demand (Map (k_aSEW :: Type) (v_aSEX :: Type)) pattern Bin' :: Demand (Map k_aSEW v_aSEX) -> Demand k_aSEW -> Demand v_aSEX -> Demand (Map k_aSEW v_aSEX) -> Demand (Map (k_aSEW :: Type) (v_aSEX :: Type)) -- | This replaces the thunk in a map partial value with the r -- parameter. This is very similar to the cap function in the -- lists example. replaceThunk :: (Shaped k, Shaped v) => Map k v -> Map k v -> Map k v -- | A helper for building a map from a list of values. fromList :: [((Int, Int), Int)] -> KMap -- | A simplified insert that ignores rebalancing since rebalancing is not -- important for the spec we will write. insert :: Ord k => k -> v -> Map k v -> Map k v -- | The lookup function specialized for knapsack. lookup :: KMap -> (Int, Int) -> Maybe Int -- | This function extracts all of the keys of a map. keys :: Map k v -> [k] -- | A lookup function that returns the default value `0` for keys that are -- not in the map. This saves us from doing repeated pattern matching -- when querying the solution table. (!) :: KMap -> (Int, Int) -> Int -- | Weight parameters to the knapsack problem. weights :: [Int] -- | Value parameters to the knapsack problem, note that this must be the -- same length as weights. values :: [Int] -- | The weight limit of the knapsack problem. limit :: Int -- | One step of the knapsack computation. This is a direct translation -- from the recurrence relation of the knapsack problem. solutionStep :: Map (Int, Int) Int -> Map (Int, Int) Int -- | The fixpoint of the recurrence relation, which is also the solution -- for the knapsack problem. solution :: Map (Int, Int) Int -- | A pattern synonym for extracting demands of each component from the -- demand of a pair. pattern Pair' :: Demand a -> Demand b -> Demand (a, b) -- | This function computes the nth pre-fixpoint of the knapsack solution, -- and looks up the value at the specified cell from the pre-fixpoint. iterSolution :: (Int, Int) -> Int -> Map (Int, Int) Int -> Maybe Int -- | This is the same as iterSolution, but uses a newtype wrapper -- for the index into the map since we want to write a customized -- Arbitrary instance for Key. iterSolutionWithKey :: Key -> Int -> Map (Int, Int) Int -> Maybe Int -- | The newtype wrapper of index into the knapsack solution table. newtype Key Key :: (Int, Int) -> Key [getKey] :: Key -> (Int, Int) -- | This IO action ties the spec together with everything built so far, -- and runs the StrictCheck randomized testing framework. runMapTest :: IO () -- | This is the specification that establishes a property important for -- the termination of solution: given any pre-fixpoint of -- `pre-solution`, forcing the value at pre-solution[i][j] should not -- induce a demand at the (i, j) cell of the input that steps to -- pre-solution, since otherwise this would be an infinite loop in the -- fixpoint. The value-lazy Map defined in this module satisfies -- this property. However, if we make this Map value-strict using -- BangPatterns, StrictCheck will report a failure when runMapTest -- is executed. iterSolution_spec :: Evaluation '[Key, Int, KMap] (Maybe Int) -> Maybe (Int, Int) instance Test.StrictCheck.Shaped.Shaped Test.StrictCheck.Examples.Map.Key instance Test.StrictCheck.Consume.Consume Test.StrictCheck.Examples.Map.Key instance Generics.SOP.Universe.HasDatatypeInfo Test.StrictCheck.Examples.Map.Key instance Generics.SOP.Universe.Generic Test.StrictCheck.Examples.Map.Key instance GHC.Classes.Ord Test.StrictCheck.Examples.Map.Key instance GHC.Classes.Eq Test.StrictCheck.Examples.Map.Key instance GHC.Show.Show Test.StrictCheck.Examples.Map.Key instance GHC.Generics.Generic Test.StrictCheck.Examples.Map.Key instance Test.QuickCheck.Arbitrary.Arbitrary Test.StrictCheck.Examples.Map.Key instance Test.StrictCheck.Produce.Produce Test.StrictCheck.Examples.Map.Key instance Test.QuickCheck.Arbitrary.Arbitrary Test.StrictCheck.Examples.Map.KMap instance Test.StrictCheck.Produce.Produce Test.StrictCheck.Examples.Map.KMap instance (Test.StrictCheck.Shaped.Shaped k, Test.StrictCheck.Shaped.Shaped v) => Test.StrictCheck.Shaped.Shaped (Test.StrictCheck.Examples.Map.Map k v) instance (Test.StrictCheck.Consume.Consume k, Test.StrictCheck.Consume.Consume v) => Test.StrictCheck.Consume.Consume (Test.StrictCheck.Examples.Map.Map k v) instance Generics.SOP.Universe.HasDatatypeInfo (Test.StrictCheck.Examples.Map.Map k v) instance Generics.SOP.Universe.Generic (Test.StrictCheck.Examples.Map.Map k v) instance (GHC.Classes.Ord k, GHC.Classes.Ord v) => GHC.Classes.Ord (Test.StrictCheck.Examples.Map.Map k v) instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Test.StrictCheck.Examples.Map.Map k v) instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Test.StrictCheck.Examples.Map.Map k v) instance GHC.Generics.Generic (Test.StrictCheck.Examples.Map.Map k v)