packages feed

generic-random 1.1.0.2 → 1.2.0.0

raw patch · 8 files changed

+273/−161 lines, 8 filesdep +deepseqdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: deepseq

Dependency ranges changed: base

API changes (from Hackage documentation)

- Generic.Random: Field :: a -> Field a
- Generic.Random: [:@] :: Gen a -> GenList g -> GenList (a : g)
- Generic.Random: [Nil] :: GenList '[]
- Generic.Random: [unField] :: Field a -> a
- Generic.Random: data GenList (g :: [Type])
- Generic.Random: field :: proxy s -> a -> Field s a
- Generic.Random: newtype Field (s :: Symbol) a
- Generic.Random.Internal.Generic: Field :: a -> Field a
- Generic.Random.Internal.Generic: [:@] :: Gen a -> GenList g -> GenList (a : g)
- Generic.Random.Internal.Generic: [Nil] :: GenList '[]
- Generic.Random.Internal.Generic: [unField] :: Field a -> a
- Generic.Random.Internal.Generic: data GenList (g :: [Type])
- Generic.Random.Internal.Generic: field :: proxy s -> a -> Field s a
- Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.GAProduct' opts f, GHC.TypeNats.KnownNat (Generic.Random.Internal.Generic.Arity f)) => Generic.Random.Internal.Generic.GAProduct 'Generic.Random.Internal.Generic.Sized opts f
- Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.GAProduct' opts f, Generic.Random.Internal.Generic.GAProduct' opts g) => Generic.Random.Internal.Generic.GAProduct' opts (f GHC.Generics.:*: g)
- Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.HasGenerators opts, Generic.Random.Internal.Generic.ArbitraryOr (Generic.Random.Internal.Generic.GeneratorsOf opts) (Generic.Random.Internal.Generic.SelectorName d) c) => Generic.Random.Internal.Generic.GAProduct' opts (GHC.Generics.S1 d (GHC.Generics.K1 i c))
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr (Generic.Random.Internal.Generic.Field n a : g) ('GHC.Base.Just n) a
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr (a : g) sel a
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr g sel a => Generic.Random.Internal.Generic.ArbitraryOr (b : g) sel a
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GAProduct' opts f => Generic.Random.Internal.Generic.GAProduct 'Generic.Random.Internal.Generic.Unsized opts f
- Generic.Random.Internal.Generic: instance Test.QuickCheck.Arbitrary.Arbitrary a => Generic.Random.Internal.Generic.ArbitraryOr '[] sel a
- Generic.Random.Internal.Generic: newtype Field (s :: Symbol) a
+ Generic.Random: (:+) :: a -> b -> (:+) a b
+ Generic.Random: FieldGen :: Gen a -> FieldGen a
+ Generic.Random: Gen1 :: (forall a. Gen a -> Gen (f a)) -> Gen1 f
+ Generic.Random: Gen1_ :: (forall a. Gen (f a)) -> Gen1_ f
+ Generic.Random: [unFieldGen] :: FieldGen a -> Gen a
+ Generic.Random: [unGen1] :: Gen1 f -> forall a. Gen a -> Gen (f a)
+ Generic.Random: [unGen1_] :: Gen1_ f -> forall a. Gen (f a)
+ Generic.Random: data a (:+) b
+ Generic.Random: fieldGen :: proxy s -> Gen a -> FieldGen s a
+ Generic.Random: listOf' :: Gen a -> Gen [a]
+ Generic.Random: listOf1' :: Gen a -> Gen [a]
+ Generic.Random: newtype FieldGen (s :: Symbol) a
+ Generic.Random: newtype Gen1 f
+ Generic.Random: newtype Gen1_ f
+ Generic.Random: sizedOptsDef :: SizedOptsDef
+ Generic.Random: type SizedOptsDef = Options 'Sized (Gen1 [] :+ ())
+ Generic.Random: vectorOf' :: Int -> Gen a -> Gen [a]
+ Generic.Random.Internal.Generic: (:+) :: a -> b -> (:+) a b
+ Generic.Random.Internal.Generic: FieldGen :: Gen a -> FieldGen a
+ Generic.Random.Internal.Generic: Gen1 :: (forall a. Gen a -> Gen (f a)) -> Gen1 f
+ Generic.Random.Internal.Generic: Gen1_ :: (forall a. Gen (f a)) -> Gen1_ f
+ Generic.Random.Internal.Generic: [unFieldGen] :: FieldGen a -> Gen a
+ Generic.Random.Internal.Generic: [unGen1] :: Gen1 f -> forall a. Gen a -> Gen (f a)
+ Generic.Random.Internal.Generic: [unGen1_] :: Gen1_ f -> forall a. Gen (f a)
+ Generic.Random.Internal.Generic: fieldGen :: proxy s -> Gen a -> FieldGen s a
+ Generic.Random.Internal.Generic: geom :: Int -> Gen Int
+ Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.HasGenerators opts, Generic.Random.Internal.Generic.ArbitraryOr gs gs (Generic.Random.Internal.Generic.SelectorName d) c, gs ~ Generic.Random.Internal.Generic.GeneratorsOf opts) => Generic.Random.Internal.Generic.GAProduct' opts (GHC.Generics.S1 d (GHC.Generics.K1 i c))
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr fg (Generic.Random.Internal.Generic.FieldGen n a Generic.Random.Internal.Generic.:+ g) ('GHC.Base.Just n) a
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr fg (Test.QuickCheck.Gen.Gen a Generic.Random.Internal.Generic.:+ g) sel a
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr fg fg 'GHC.Base.Nothing a => Generic.Random.Internal.Generic.ArbitraryOr fg (Generic.Random.Internal.Generic.Gen1 f Generic.Random.Internal.Generic.:+ g) sel (f a)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ArbitraryOr fg g sel a => Generic.Random.Internal.Generic.ArbitraryOr fg (b Generic.Random.Internal.Generic.:+ g) sel a
+ Generic.Random.Internal.Generic: instance Test.QuickCheck.Arbitrary.Arbitrary a => Generic.Random.Internal.Generic.ArbitraryOr fg () sel a
+ Generic.Random.Internal.Generic: instance forall k fg (f :: k -> *) g (sel :: GHC.Base.Maybe GHC.Types.Symbol) (a :: k). Generic.Random.Internal.Generic.ArbitraryOr fg (Generic.Random.Internal.Generic.Gen1_ f Generic.Random.Internal.Generic.:+ g) sel (f a)
+ Generic.Random.Internal.Generic: instance forall k opts (d :: GHC.Generics.Meta) (f :: k -> *). Generic.Random.Internal.Generic.GAProduct' opts (GHC.Generics.S1 d f) => Generic.Random.Internal.Generic.GAProduct 'Generic.Random.Internal.Generic.Sized opts (GHC.Generics.S1 d f)
+ Generic.Random.Internal.Generic: instance forall k opts (f :: k -> *) (g :: k -> *). (Generic.Random.Internal.Generic.GAProduct' opts f, Generic.Random.Internal.Generic.GAProduct' opts g) => Generic.Random.Internal.Generic.GAProduct' opts (f GHC.Generics.:*: g)
+ Generic.Random.Internal.Generic: instance forall k opts (f :: k -> *). (Generic.Random.Internal.Generic.GAProduct' opts f, GHC.TypeNats.KnownNat (Generic.Random.Internal.Generic.Arity f)) => Generic.Random.Internal.Generic.GAProduct 'Generic.Random.Internal.Generic.Sized opts f
+ Generic.Random.Internal.Generic: instance forall k opts (f :: k -> *). Generic.Random.Internal.Generic.GAProduct' opts f => Generic.Random.Internal.Generic.GAProduct 'Generic.Random.Internal.Generic.Unsized opts f
+ Generic.Random.Internal.Generic: listOf' :: Gen a -> Gen [a]
+ Generic.Random.Internal.Generic: listOf1' :: Gen a -> Gen [a]
+ Generic.Random.Internal.Generic: newtype FieldGen (s :: Symbol) a
+ Generic.Random.Internal.Generic: newtype Gen1 f
+ Generic.Random.Internal.Generic: newtype Gen1_ f
+ Generic.Random.Internal.Generic: sizedOptsDef :: SizedOptsDef
+ Generic.Random.Internal.Generic: type SizedOptsDef = Options 'Sized (Gen1 [] :+ ())
+ Generic.Random.Internal.Generic: vectorOf' :: Int -> Gen a -> Gen [a]
- Generic.Random: data Options (s :: Sizing) (g :: [Type])
+ Generic.Random: data Options (s :: Sizing) (genList :: Type)
- Generic.Random: genericArbitrary' :: (GArbitrary SizedOpts a, BaseCase a) => Weights a -> Gen a
+ Generic.Random: genericArbitrary' :: (GArbitrary SizedOptsDef a, BaseCase a) => Weights a -> Gen a
- Generic.Random: genericArbitraryG :: (GArbitrary (SetGens g UnsizedOpts) a) => GenList g -> Weights a -> Gen a
+ Generic.Random: genericArbitraryG :: (GArbitrary (SetGens genList UnsizedOpts) a) => genList -> Weights a -> Gen a
- Generic.Random: genericArbitraryRec :: (GArbitrary SizedOpts a) => Weights a -> Gen a
+ Generic.Random: genericArbitraryRec :: (GArbitrary SizedOptsDef a) => Weights a -> Gen a
- Generic.Random: genericArbitraryRecG :: (GArbitrary (SetGens g SizedOpts) a) => GenList g -> Weights a -> Gen a
+ Generic.Random: genericArbitraryRecG :: (GArbitrary (SetGens genList SizedOpts) a) => genList -> Weights a -> Gen a
- Generic.Random: genericArbitrarySingleG :: (GArbitrary (SetGens g UnsizedOpts) a, Weights_ (Rep a) ~ L c0) => GenList g -> Gen a
+ Generic.Random: genericArbitrarySingleG :: (GArbitrary (SetGens genList UnsizedOpts) a, Weights_ (Rep a) ~ L c0) => genList -> Gen a
- Generic.Random: genericArbitraryU' :: (GArbitrary SizedOpts a, BaseCase a, GUniformWeight a) => Gen a
+ Generic.Random: genericArbitraryU' :: (GArbitrary SizedOptsDef a, BaseCase a, GUniformWeight a) => Gen a
- Generic.Random: genericArbitraryUG :: (GArbitrary (SetGens g UnsizedOpts) a, GUniformWeight a) => GenList g -> Gen a
+ Generic.Random: genericArbitraryUG :: (GArbitrary (SetGens genList UnsizedOpts) a, GUniformWeight a) => genList -> Gen a
- Generic.Random: setGenerators :: GenList g -> Options s g0 -> Options s g
+ Generic.Random: setGenerators :: genList -> Options s g0 -> Options s genList
- Generic.Random: type SizedOpts = (Options 'Sized '[] :: Type)
+ Generic.Random: type SizedOpts = Options 'Sized ()
- Generic.Random: type UnsizedOpts = (Options 'Unsized '[] :: Type)
+ Generic.Random: type UnsizedOpts = Options 'Unsized ()
- Generic.Random.Internal.BaseCase: genericArbitrary' :: (GArbitrary SizedOpts a, BaseCase a) => Weights a -> Gen a
+ Generic.Random.Internal.BaseCase: genericArbitrary' :: (GArbitrary SizedOptsDef a, BaseCase a) => Weights a -> Gen a
- Generic.Random.Internal.BaseCase: genericArbitraryU' :: (GArbitrary SizedOpts a, BaseCase a, GUniformWeight a) => Gen a
+ Generic.Random.Internal.BaseCase: genericArbitraryU' :: (GArbitrary SizedOptsDef a, BaseCase a, GUniformWeight a) => Gen a
- Generic.Random.Internal.Generic: Options :: GenList g -> Options
+ Generic.Random.Internal.Generic: Options :: genList -> Options
- Generic.Random.Internal.Generic: [_generators] :: Options -> GenList g
+ Generic.Random.Internal.Generic: [_generators] :: Options -> genList
- Generic.Random.Internal.Generic: arbitraryOr :: ArbitraryOr g sel a => proxy sel -> GenList g -> Gen a
+ Generic.Random.Internal.Generic: arbitraryOr :: ArbitraryOr fullGenList genList sel a => proxy sel -> fullGenList -> genList -> Gen a
- Generic.Random.Internal.Generic: class ArbitraryOr (g :: [Type]) (sel :: Maybe Symbol) a
+ Generic.Random.Internal.Generic: class ArbitraryOr (fullGenList :: Type) (genList :: Type) (sel :: Maybe Symbol) a
- Generic.Random.Internal.Generic: data a (:|) b
+ Generic.Random.Internal.Generic: data a (:+) b
- Generic.Random.Internal.Generic: generators :: HasGenerators opts => opts -> GenList (GeneratorsOf opts)
+ Generic.Random.Internal.Generic: generators :: HasGenerators opts => opts -> GeneratorsOf opts
- Generic.Random.Internal.Generic: genericArbitraryG :: (GArbitrary (SetGens g UnsizedOpts) a) => GenList g -> Weights a -> Gen a
+ Generic.Random.Internal.Generic: genericArbitraryG :: (GArbitrary (SetGens genList UnsizedOpts) a) => genList -> Weights a -> Gen a
- Generic.Random.Internal.Generic: genericArbitraryRec :: (GArbitrary SizedOpts a) => Weights a -> Gen a
+ Generic.Random.Internal.Generic: genericArbitraryRec :: (GArbitrary SizedOptsDef a) => Weights a -> Gen a
- Generic.Random.Internal.Generic: genericArbitraryRecG :: (GArbitrary (SetGens g SizedOpts) a) => GenList g -> Weights a -> Gen a
+ Generic.Random.Internal.Generic: genericArbitraryRecG :: (GArbitrary (SetGens genList SizedOpts) a) => genList -> Weights a -> Gen a
- Generic.Random.Internal.Generic: genericArbitrarySingleG :: (GArbitrary (SetGens g UnsizedOpts) a, Weights_ (Rep a) ~ L c0) => GenList g -> Gen a
+ Generic.Random.Internal.Generic: genericArbitrarySingleG :: (GArbitrary (SetGens genList UnsizedOpts) a, Weights_ (Rep a) ~ L c0) => genList -> Gen a
- Generic.Random.Internal.Generic: genericArbitraryUG :: (GArbitrary (SetGens g UnsizedOpts) a, GUniformWeight a) => GenList g -> Gen a
+ Generic.Random.Internal.Generic: genericArbitraryUG :: (GArbitrary (SetGens genList UnsizedOpts) a, GUniformWeight a) => genList -> Gen a
- Generic.Random.Internal.Generic: newtype Options (s :: Sizing) (g :: [Type])
+ Generic.Random.Internal.Generic: newtype Options (s :: Sizing) (genList :: Type)
- Generic.Random.Internal.Generic: setGenerators :: GenList g -> Options s g0 -> Options s g
+ Generic.Random.Internal.Generic: setGenerators :: genList -> Options s g0 -> Options s genList
- Generic.Random.Internal.Generic: type SizedOpts = (Options 'Sized '[] :: Type)
+ Generic.Random.Internal.Generic: type SizedOpts = Options 'Sized ()
- Generic.Random.Internal.Generic: type UnsizedOpts = (Options 'Unsized '[] :: Type)
+ Generic.Random.Internal.Generic: type UnsizedOpts = Options 'Unsized ()

Files

CHANGELOG.md view
@@ -1,5 +1,20 @@ https://github.com/Lysxia/generic-random/blob/master/changelog.md +# 1.2.0.0++- Fix a bug where generators did not decrease the size parameter with+  single-field constructors++- The sized generators now use a custom generator for lists.+  Use `genericArbitraryRecG ()` to disable that.++- Lists of custom generators are now constructed using `(:+)` instead of+  `GenList`+- Rename `Field` to `FieldGen`+- Add `Gen1`, `Gen1_` (custom generators for unary type constructors)+- Add `listOf'`, `listOf1'`, `vectorOf'`+- Remove deprecated module `Generic.Random.Generic`+ # 1.1.0.2  - Improved performance
generic-random.cabal view
@@ -1,5 +1,5 @@ name:                generic-random-version:             1.1.0.2+version:             1.2.0.0 synopsis:            Generic random generators description:     For more information@@ -20,18 +20,17 @@ build-type:          Simple extra-source-files:  README.md CHANGELOG.md cabal-version:       >=1.10-tested-with:         GHC == 8.0.1, GHC == 8.2.1+tested-with:         GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1, GHC == 8.2.1, GHC == 8.4.1  library   hs-source-dirs:      src   exposed-modules:     Generic.Random-    Generic.Random.Generic     Generic.Random.Internal.BaseCase     Generic.Random.Internal.Generic     Generic.Random.Tutorial   build-depends:-    base >= 4.7 && < 4.11,+    base >= 4.7 && < 4.12,     QuickCheck   default-language:    Haskell2010   ghc-options: -Wall -fno-warn-name-shadowing@@ -45,6 +44,7 @@   Main-is:         Unit.hs   Build-depends:       base,+      deepseq,       QuickCheck,       generic-random   Type: exitcode-stdio-1.0
src/Generic/Random.hs view
@@ -37,21 +37,30 @@   , Options ()   , SizedOpts   , sizedOpts+  , SizedOptsDef+  , sizedOptsDef   , UnsizedOpts   , unsizedOpts   , Sizing (..)   , setSized   , setUnsized-  , GenList (..)+  , (:+) (..) #if __GLASGOW_HASKELL__ >= 800-  , Field (..)-  , field+  , FieldGen (..)+  , fieldGen #endif+  , Gen1 (..)+  , Gen1_ (..)   , setGenerators      -- * Public classes   , GArbitrary   , GUniformWeight++    -- * Helpful combinators+  , listOf'+  , listOf1'+  , vectorOf'   ) where  import Generic.Random.Internal.BaseCase
− src/Generic/Random/Generic.hs
@@ -1,7 +0,0 @@--- | Reexport of "Generic.Random", for backwards-compatibility.--module Generic.Random.Generic-       {-# DEPRECATED "Use Generic.Random instead" #-}-       ( module Generic.Random ) where--import Generic.Random
src/Generic/Random/Internal/BaseCase.hs view
@@ -36,8 +36,10 @@ -- recursive types, looking for base cases once the size reaches 0. -- -- > genericArbitrary' (17 % 19 % 23 % ()) :: Gen a+--+-- N.B.: This replaces fields of type @[t]@ with @'listOf'' arbitrary@. genericArbitrary'-  :: (GArbitrary SizedOpts a, BaseCase a)+  :: (GArbitrary SizedOptsDef a, BaseCase a)   => Weights a  -- ^ List of weights for every constructor   -> Gen a genericArbitrary' w = genericArbitraryRec w `withBaseCase` baseCase@@ -45,8 +47,10 @@ -- | Equivalent to @'genericArbitrary'' 'uniform'@. -- -- > genericArbitraryU :: Gen a+--+-- N.B.: This replaces fields of type @[t]@ with @'listOf'' arbitrary@. genericArbitraryU'-  :: (GArbitrary SizedOpts a, BaseCase a, GUniformWeight a)+  :: (GArbitrary SizedOptsDef a, BaseCase a, GUniformWeight a)   => Gen a genericArbitraryU' = genericArbitrary' uniform 
src/Generic/Random/Internal/Generic.hs view
@@ -8,6 +8,8 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}@@ -34,7 +36,7 @@ import GHC.Generics hiding (S, Arity) #endif import GHC.TypeLits (KnownNat, Nat, Symbol, type (+), natVal)-import Test.QuickCheck (Arbitrary(..), Gen, choose, resize, sized)+import Test.QuickCheck (Arbitrary(..), Gen, choose, scale, sized, vectorOf)  #if __GLASGOW_HASKELL__ < 800 #define Type *@@ -79,11 +81,13 @@ -- at size 0. -- -- > genericArbitraryRec (7 % 11 % 13 % ()) :: Gen a+--+-- N.B.: This replaces fields of type @[t]@ with @'listOf'' arbitrary@. genericArbitraryRec-  :: (GArbitrary SizedOpts a)+  :: (GArbitrary SizedOptsDef a)   => Weights a  -- ^ List of weights for every constructor   -> Gen a-genericArbitraryRec = genericArbitraryWith sizedOpts+genericArbitraryRec = genericArbitraryWith sizedOptsDef  -- | 'genericArbitrary' with explicit generators. --@@ -107,8 +111,8 @@ -- (i.e., either @a@ or @'Field' "x" a@), the generator for the first -- match will be picked. genericArbitraryG-  :: (GArbitrary (SetGens g UnsizedOpts) a)-  => GenList g+  :: (GArbitrary (SetGens genList UnsizedOpts) a)+  => genList   -> Weights a   -> Gen a genericArbitraryG gs = genericArbitraryWith opts@@ -118,24 +122,24 @@ -- | 'genericArbitraryU' with explicit generators. -- See also 'genericArbitraryG'. genericArbitraryUG-  :: (GArbitrary (SetGens g UnsizedOpts) a, GUniformWeight a)-  => GenList g+  :: (GArbitrary (SetGens genList UnsizedOpts) a, GUniformWeight a)+  => genList   -> Gen a genericArbitraryUG gs = genericArbitraryG gs uniform  -- | 'genericArbitrarySingle' with explicit generators. -- See also 'genericArbitraryG'. genericArbitrarySingleG-  :: (GArbitrary (SetGens g UnsizedOpts) a, Weights_ (Rep a) ~ L c0)-  => GenList g+  :: (GArbitrary (SetGens genList UnsizedOpts) a, Weights_ (Rep a) ~ L c0)+  => genList   -> Gen a genericArbitrarySingleG = genericArbitraryUG  -- | 'genericArbitraryRec' with explicit generators. -- See also 'genericArbitraryG'. genericArbitraryRecG-  :: (GArbitrary (SetGens g SizedOpts) a)-  => GenList g+  :: (GArbitrary (SetGens genList SizedOpts) a)+  => genList   -> Weights a  -- ^ List of weights for every constructor   -> Gen a genericArbitraryRecG gs = genericArbitraryWith opts@@ -270,22 +274,29 @@   -- | Type-level options for 'GArbitrary'.-newtype Options (s :: Sizing) (g :: [Type]) = Options-  { _generators :: GenList g+newtype Options (s :: Sizing) (genList :: Type) = Options+  { _generators :: genList   } +-- | Default options for unsized generators. unsizedOpts :: UnsizedOpts-unsizedOpts = Options Nil+unsizedOpts = Options () +-- | Default options for sized generators. sizedOpts :: SizedOpts-sizedOpts = Options Nil+sizedOpts = Options () +-- | Default options overriding the list generator using `listOf'`.+sizedOptsDef :: SizedOptsDef+sizedOptsDef = Options (Gen1 listOf' :+ ()) + -- | Whether to decrease the size parameter before generating fields. data Sizing = Sized | Unsized -type UnsizedOpts = (Options 'Unsized '[] :: Type)-type SizedOpts = (Options 'Sized '[] :: Type)+type UnsizedOpts = Options 'Unsized ()+type SizedOpts = Options 'Sized ()+type SizedOptsDef = Options 'Sized (Gen1 [] :+ ())  type family SizingOf opts :: Sizing type instance SizingOf (Options s _g) = s@@ -300,41 +311,82 @@ setUnsized = coerce  -- | Heterogeneous list of generators.-data GenList (g :: [Type]) where-  Nil :: GenList '[]-  (:@) :: Gen a -> GenList g -> GenList (a ': g)+data a :+ b = a :+ b -infixr 3 :@+infixr 1 :+ -type family GeneratorsOf opts :: [Type]++type family GeneratorsOf opts :: Type type instance GeneratorsOf (Options _s g) = g  class HasGenerators opts where-  generators :: opts -> GenList (GeneratorsOf opts)+  generators :: opts -> GeneratorsOf opts  instance HasGenerators (Options s g) where   generators = _generators -setGenerators :: GenList g -> Options s g0 -> Options s g+setGenerators :: genList -> Options s g0 -> Options s genList setGenerators gens (Options _) = Options gens  -type family SetGens (g :: [Type]) opts+type family SetGens (g :: Type) opts type instance SetGens g (Options s _g) = Options s g  #if __GLASGOW_HASKELL__ >= 800--- | A marker for a generator which overrides a specific field--- named @s@.+-- | A generator which overrides a specific field named @s@. -- -- /Available only for @base >= 4.9@./-newtype Field (s :: Symbol) a = Field { unField :: a }+newtype FieldGen (s :: Symbol) a = FieldGen { unFieldGen :: Gen a }  -- | 'Field' constructor with the field name given via a proxy.-field :: proxy s -> a -> Field s a-field _ = Field+fieldGen :: proxy s -> Gen a -> FieldGen s a+fieldGen _ = FieldGen #endif +-- | Generators for containers of kind @* -> *@, parameterized by+-- the generator for each element.+newtype Gen1 f = Gen1 { unGen1 :: forall a. Gen a -> Gen (f a) } +-- | Generators for unary type constructors that are not containers.+newtype Gen1_ f = Gen1_ { unGen1_ :: forall a. Gen (f a) }++-- | An alternative to 'vectorOf' that divides the size parameter by the+-- length of the list.+vectorOf' :: Int -> Gen a -> Gen [a]+vectorOf' 0 = \_ -> pure []+vectorOf' i = scale (`div` i) . vectorOf i++-- | An alternative to 'listOf' that divides the size parameter by the+-- length of the list.+-- The length follows a geometric distribution of parameter+-- @1/(sqrt size + 1)@.+listOf' :: Gen a -> Gen [a]+listOf' g = sized $ \n -> do+  i <- geom n+  vectorOf' i g++-- | An alternative to 'listOf1' (nonempty lists) that divides the size+-- parameter by the length of the list.+-- The length (minus one) follows a geometric distribution of parameter+-- @1/(sqrt size + 1)@.+listOf1' :: Gen a -> Gen [a]+listOf1' g = liftA2 (:) g (listOf' g)++-- | Geometric distribution of parameter @1/(sqrt n + 1)@ (@n >= 0@).+geom :: Int -> Gen Int+geom 0 = pure 0+geom n = go 0 where+  n' = fromIntegral n+  p = 1 / (sqrt n' + 1) :: Double+  go r = do+    x <- choose (0, 1)+    if x < p then+      pure r+    else+      go $! (r + 1)++---+ -- | Generic Arbitrary class GA opts f where   ga :: opts -> Weights_ f -> Int -> Gen (f p)@@ -382,8 +434,13 @@   gaProduct _ = gaProduct'   {-# INLINE gaProduct #-} +-- Single-field constructors: decrease size by 1.+instance {-# OVERLAPPING #-} GAProduct' opts (S1 d f)+  => GAProduct 'Sized opts (S1 d f) where+  gaProduct _ = scale (\n -> max 0 (n-1)) . gaProduct'+ instance (GAProduct' opts f, KnownNat (Arity f)) => GAProduct 'Sized opts f where-  gaProduct _ opts = sized $ \n -> resize (n `div` arity) (gaProduct' opts)+  gaProduct _ = scale (`div` arity) . gaProduct'     where       arity = fromInteger (natVal (Proxy :: Proxy (Arity f)))   {-# INLINE gaProduct #-}@@ -400,10 +457,15 @@   gaProduct' _ = pure U1   {-# INLINE gaProduct' #-} -instance (HasGenerators opts, ArbitraryOr (GeneratorsOf opts) (SelectorName d) c)+instance+  ( HasGenerators opts+  , ArbitraryOr gs gs (SelectorName d) c+  , gs ~ GeneratorsOf opts )   => GAProduct' opts (S1 d (K1 i c)) where-  gaProduct' opts = fmap (M1 . K1) (arbitraryOr sel (generators opts))-    where sel = Proxy :: Proxy (SelectorName d)+  gaProduct' opts = fmap (M1 . K1) (arbitraryOr sel gs gs)+    where+      sel = Proxy :: Proxy (SelectorName d)+      gs = generators opts   {-# INLINE gaProduct' #-}  instance (GAProduct' opts f, GAProduct' opts g) => GAProduct' opts (f :*: g) where@@ -417,32 +479,39 @@   Arity (M1 _i _c _f) = 1  -class ArbitraryOr (g :: [Type]) (sel :: Maybe Symbol) a where-  arbitraryOr :: proxy sel -> GenList g -> Gen a+class ArbitraryOr (fullGenList :: Type) (genList :: Type) (sel :: Maybe Symbol) a where+  arbitraryOr :: proxy sel -> fullGenList -> genList -> Gen a -instance {-# INCOHERENT #-} ArbitraryOr (a ': g) sel a where-  arbitraryOr _ (gen :@ _) = gen+instance {-# INCOHERENT #-} ArbitraryOr fg (Gen a :+ g) sel a where+  arbitraryOr _ _ (gen :+ _) = gen   {-# INLINE arbitraryOr #-} -instance {-# OVERLAPPABLE #-} ArbitraryOr g sel a => ArbitraryOr (b ': g) sel a where-  arbitraryOr sel (_ :@ gens) = arbitraryOr sel gens+instance {-# OVERLAPPABLE #-} ArbitraryOr fg g sel a => ArbitraryOr fg (b :+ g) sel a where+  arbitraryOr sel fg (_ :+ gens) = arbitraryOr sel fg gens   {-# INLINE arbitraryOr #-} -instance Arbitrary a => ArbitraryOr '[] sel a where-  arbitraryOr _ _ = arbitrary+instance Arbitrary a => ArbitraryOr fg () sel a where+  arbitraryOr _ _ _ = arbitrary   {-# INLINE arbitraryOr #-}  #if __GLASGOW_HASKELL__ >= 800-instance {-# INCOHERENT #-} ArbitraryOr (Field n a ': g) ('Just n) a where-  arbitraryOr _ (gen :@ _) = coerce gen+instance {-# INCOHERENT #-} ArbitraryOr fg (FieldGen n a :+ g) ('Just n) a where+  arbitraryOr _ _ (FieldGen gen :+ _) = gen   {-# INLINE arbitraryOr #-}  type family SelectorName (d :: Meta) :: Maybe Symbol-type instance SelectorName (MetaSel mn su ss ds) = mn+type instance SelectorName ('MetaSel mn su ss ds) = mn #else type SelectorName d = (Nothing :: Maybe Symbol) #endif +instance {-# INCOHERENT #-} ArbitraryOr fg (Gen1_ f :+ g) sel (f a) where+  arbitraryOr _ _ (Gen1_ gen :+ _) = gen++instance {-# INCOHERENT #-} ArbitraryOr fg fg 'Nothing a+  => ArbitraryOr fg (Gen1 f :+ g) sel (f a) where+  arbitraryOr _ fg (Gen1 gen :+ _) = gen (arbitraryOr noSel fg fg)+    where noSel = Proxy :: Proxy 'Nothing  newtype Weighted a = Weighted (Maybe (Int -> Gen a, Int))   deriving Functor
src/Generic/Random/Tutorial.hs view
@@ -2,13 +2,13 @@ -- [QuickCheck](https://hackage.haskell.org/package/QuickCheck)'s -- @arbitrary@. ----- == Example+-- = Example -- -- Define your type. -- -- @ -- data Tree a = Leaf a | Node (Tree a) (Tree a)---   deriving 'Generic'+--   deriving 'GHC.Generics.Generic' -- @ -- -- Pick an 'arbitrary' implementation, specifying the required distribution of@@ -16,7 +16,7 @@ -- -- @ -- instance Arbitrary a => Arbitrary (Tree a) where---   arbitrary = 'genericArbitrary' (8 '%' 9 '%' ())+--   arbitrary = 'genericArbitrary' (9 '%' 8 '%' ()) -- @ -- -- @arbitrary :: 'Gen' (Tree a)@ picks a @Leaf@ with probability 9\/17, or a@@ -34,7 +34,7 @@ --     ] -- @ ----- == Distribution of constructors+-- = Distribution of constructors -- -- The distribution of constructors can be specified as -- a special list of /weights/ in the same order as the data type definition.@@ -45,7 +45,7 @@ -- the unit @()@ as the empty list, in the order corresponding to the data type -- definition. The uniform distribution can be obtained with 'uniform'. ----- === Uniform distribution+-- == Uniform distribution -- -- You can specify the uniform distribution (all weights equal) with 'uniform'. -- ('genericArbitraryU' is available as a shorthand for@@ -54,7 +54,7 @@ -- Note that for many recursive types, a uniform distribution tends to produce -- big or even infinite values. ----- === Typed weights+-- == Typed weights -- -- /GHC 8.0.1 and above only (base ≥ 4.9)./ --@@ -66,7 +66,7 @@ -- -- @ -- ((x :: 'W' \"Leaf\") '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a)--- (x '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a)+-- ( x              '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a) -- @ -- -- This will not.@@ -75,113 +75,107 @@ -- ((x :: 'W' \"Node\") '%' y '%' ()) :: 'Weights' (Tree a) -- -- Requires an order of constructors different from the definition of the @Tree@ type. ----- (x '%' y '%' z '%' ()) :: 'Weights' (Tree a)+-- ( x              '%' y '%' z '%' ()) :: 'Weights' (Tree a) -- -- Doesn't have the right number of weights. -- @ ----- == Ensuring termination+-- = Ensuring termination -- -- As mentioned earlier, one must be careful with recursive types -- to avoid producing extremely large values.+-- The alternative generator 'genericArbitraryRec' decreases the size+-- parameter at every call to keep values at reasonable sizes,+-- to be used together with 'withBaseCase'. ----- The alternative generator 'genericArbitrary'' implements a simple strategy to keep--- values at reasonable sizes: the size parameter of 'Gen' is divided among the--- fields of the chosen constructor. When it reaches zero, the generator--- selects a small term of the given type. This generally ensures that the--- number of constructors remains close to the initial size parameter passed to--- 'Gen'.+-- For example, we may provide a base case consisting of only `Leaf`: -- -- @--- 'genericArbitrary'' (x1 '%' ... '%' xn '%' ())+-- instance Arbitrary a => Arbitrary (Tree a) where+--   arbitrary = 'genericArbitraryRec' (1 '%' 2 '%' ())+--     ``withBaseCase`` (Leaf \<$\> arbitrary) -- @ ----- Here is an example with nullary constructors:+-- That is equivalent to the following definition. Note the+-- 'Test.QuickCheck.resize' modifier. -- -- @--- data Bush = Leaf1 | Leaf2 | Node3 Bush Bush Bush---   deriving Generic------ instance Arbitrary Bush where---   arbitrary = 'genericArbitrary'' (1 '%' 2 '%' 3 '%' ())+-- arbitrary :: Arbitrary a => Gen (Tree a)+-- arbitrary = sized $ \\n ->+--   -- "if" condition from withBaseCase+--   if n == 0 then+--     Leaf \<$\> arbitrary+--   else+--     -- genericArbitraryRec+--     frequency+--       [ (1, resize (max 0 (n - 1)) (Leaf \<$\> arbitrary))+--       , (2, resize (n \`div\` 2)     (Node \<$\> arbitrary \<*\> arbitrary))+--       ] -- @ ----- Here, 'genericArbitrary'' is equivalent to:+-- The resizing strategy is as follows:+-- the size parameter of 'Gen' is divided among the fields of the chosen+-- constructor, or decreases by one if the constructor is unary.+-- @'withBaseCase' defG baseG@ is equal to @defG@ as long as the size parameter+-- is nonzero, and it becomes @baseG@ once the size reaches zero.+-- This combination generally ensures that the number of constructors remains+-- close to the initial size parameter passed to 'Gen'. ----- @--- 'genericArbitrary'' :: 'Weights' Bush -> Gen Bush--- 'genericArbitrary'' (x '%' y '%' z '%' ()) =---   sized $ \\n ->---     if n == 0 then---       -- If the size parameter is zero, only nullary alternatives are kept.---       elements [Leaf1, Leaf2]---     else---       frequency---         [ (x, return Leaf1)---         , (y, return Leaf2)---         , (z, resize (n \`div\` 3) node)  -- 3 because Node3 is 3-ary---         ]---   where---     node = Node3 \<$\> arbitrary \<*\> arbitrary \<*\> arbitrary--- @+-- == Automatic base case discovery ----- If we want to generate a value of type @Tree ()@, there is a--- value of depth 1 that we can use to end recursion: @Leaf ()@.+-- In some situations, generic-random can also construct base cases automatically.+-- This works best with fully concrete types (no type parameters). -- -- @--- 'genericArbitrary'' :: 'Weights' (Tree ()) -> Gen (Tree ())--- 'genericArbitrary'' (x '%' y '%' ()) =---   sized $ \\n ->---     if n == 0 then---       return (Leaf ())---     else---       frequency---         [ (x, Leaf \<$\> arbitrary)---         , (y, resize (n \`div\` 2) $ Node \<$\> arbitrary \<*\> arbitrary)---         ]+-- {-\# LANGUAGE FlexibleInstances #-}+--+-- instance Arbitrary (Tree ()) where+--   arbitrary = 'genericArbitrary'' (1 '%' 2 '%' ()) -- @ ----- Because the argument of @Tree@ must be inspected in order to discover--- values of type @Tree ()@, we incur some extra constraints if we want--- polymorphism.+-- The above instance will infer the value @Leaf ()@ as a base case. --+-- To discover values of type @Tree a@, we must inspect the type argument @a@,+-- thus we incur some extra constraints if we want polymorphism.+-- It is preferrable to apply the type class 'BaseCase' to the instance head+-- (@Tree a@) as follows, as it doesn't reduce to something worth seeing.+-- -- @ -- {-\# LANGUAGE FlexibleContexts, UndecidableInstances \#-} ----- instance (Arbitrary a, BaseCase (Tree a))+-- instance (Arbitrary a, 'BaseCase' (Tree a)) --   => Arbitrary (Tree a) where --   arbitrary = 'genericArbitrary'' (1 '%' 2 '%' ()) -- @ ----- By default, the 'BaseCase' type class looks for all values of minimal depth--- (constructors have depth @1 + max(0, depths of fields)@).------ This can easily be overriden by declaring a specialized 'BaseCase' instance,--- such as this one:+-- The 'BaseCase' type class finds values of minimal depth,+-- where the depth of a constructor is defined as @1 + max(0, depths of fields)@,+-- e.g., @Leaf ()@ has depth 2. ----- @--- instance Arbitrary a => 'BaseCase' (Tree a) where---   'baseCase' = oneof [leaf, simpleNode]---     where---       leaf = Leaf \<$\> arbitrary---       simpleNode = Node \<$\> leaf \<*\> leaf--- @+-- == Note about lists ----- An alternative base case can also be specified directly in the `arbitrary`--- definition with the 'withBaseCase' combinator.+-- The @Arbitrary@ instance for lists can be problematic for this way+-- of implementing recursive sized generators, because they make a lot of+-- recursive calls to 'arbitrary' without decreasing the size parameter.+-- Hence, as a default, 'genericArbitraryRec' also detects fields which are+-- lists to replace 'arbitrary' with a different generator that divides+-- the size parameter by the length of the list before generating each+-- eleement. This uses the customizable mechanism shown in the next section. ----- 'genericArbitraryRec' is a variant of 'genericArbitrary'' with no base case.+-- If you really want to use 'arbitrary' for lists in the derived instances,+-- substitute @'genericArbitraryRec'@ with @'genericArbitraryRecG' ()@. -- -- @--- instance Arbitrary Bush where---   arbitrary =---     'genericArbitraryRec' (1 '%' 2 '%' 3 '%' ())---       \`withBaseCase\` return Leaf1+-- arbitrary = 'genericArbitraryRecG' ()+--   ``withBaseCase`` baseGen -- @ ----- == Custom generators for some fields+-- Some combinators are available for further tweaking: 'listOf'', 'listOf1'',+-- 'vectorOf''. --+-- = Custom generators for some fields+-- -- Sometimes, a few fields may need custom generators instead of 'arbitrary'.--- For example, imagine here that String is meant to represent+-- For example, imagine here that @String@ is meant to represent -- alphanumerical strings only, and that IDs are meant to be nonnegative, -- whereas balances can have any sign. --@@ -190,42 +184,53 @@ --   userName :: String, --   userId :: Int, --   userBalance :: Int---   } deriving 'Generic'+--   } deriving 'GHC.Generics.Generic' -- @ ----- - @'Arbitrary' String@ may generate any unicode characters,+-- - @'Test.QuickCheck.Arbitrary' String@ may generate any unicode character, --   alphanumeric or not;--- - @'Arbitrary' Int@ may generate negative values;+-- - @'Test.QuickCheck.Arbitrary' Int@ may generate negative values; -- - using @newtype@ wrappers or passing generators explicitly to properties --   may be impractical (the maintenance overhead can be high because the types --   are big or change often). ----- Using generic-random, the alternative is to declare a (heterogeneous) list--- of generators to be used when generating certain fields...+-- Using generic-random, we can declare a (heterogeneous) list of generators to+-- be used when generating certain fields (remember to end lists with @()@). -- -- @--- customGens :: 'GenList' '['Field' "userId" Int, String]+-- customGens :: 'FieldGen' "userId" Int ':+' Gen String ':+' () -- customGens =---   ('Field' . 'getNonNegative' \<$\> arbitrary) ':@'---   ('listOf' ('elements' (filter isAlphaNum [minBound .. maxBound]))) ':@'---   'Nil'+--   ('FieldGen' . 'getNonNegative' \<$\> arbitrary) ':+'+--   ('listOf' ('elements' (filter isAlphaNum [minBound .. maxBound]))) ':+'+--   () -- @ ----- And to use the 'genericArbitraryG' and variants that accept those explicit--- generators.+-- Now we use the 'genericArbitraryG' combinator and other @G@-suffixed+-- variants that accept those explicit generators. -- -- - All @String@ fields will use the provided generator of --   alphanumeric strings; -- - the field @"userId"@ of type @Int@ will use the generator---   of nonnegative integers (the 'Field' type is special);+--   of nonnegative integers; -- - everything else defaults to 'arbitrary'. -- -- @ -- instance Arbitrary User where --   arbitrary = 'genericArbitrarySingleG' customGens -- @+--+-- The custom generator modifiers that can occur in the list are:+--+-- - 'Test.QuickCheck.Gen': a generator for a specific type;+-- - 'FieldGen': a generator for a field name and type;+-- - 'Gen1': a generator for containers, parameterized by a generator+--   for individual elements;+-- - 'Gen1_': a generator for unary type constructors that are not+--   containers.+--+-- Suggestions to add more modifiers or otherwise improve this tutorial are welcome!+-- <https://github.com/Lysxia/generic-random/issues The issue tracker is this way.>  module Generic.Random.Tutorial () where -import GHC.Generics import Generic.Random
test/Unit.hs view
@@ -1,29 +1,46 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}-#if __GLASGOW_HASKELL__ < 710-{-# LANGUAGE OverlappingInstances #-}-#endif -import GHC.Generics+import Control.Monad (replicateM)+import Control.DeepSeq (NFData, force)+import GHC.Generics (Generic)+import System.Timeout (timeout)+ import Test.QuickCheck -import Generic.Random.Generic+import Generic.Random  newtype T a = W a deriving (Generic, Show)  instance (Arbitrary a, BaseCase (T a)) => Arbitrary (T a) where   arbitrary = genericArbitrary' uniform +instance NFData a => NFData (T a)+ f :: Gen (T (T Int)) f = arbitrary ++data NTree = Leaf | Node [NTree] deriving (Generic, Show)++instance Arbitrary NTree where+  arbitrary = genericArbitraryU'++instance NFData NTree++eval :: NFData a => String -> Gen a -> IO ()+eval name g = do+  x <- timeout (10 ^ 6) $ do+    xs <- replicateM 100 (generate g)+    return $! force xs+  case x of+    Just _ -> return ()+    Nothing -> fail $ name ++ ": did not finish on time"+ main :: IO ()-main = sample' f >>= force-  where-    force [] = return ()-    force (x : xs) = x `seq` force xs+main = do+  eval "T" (arbitrary :: Gen (T (T Int)))+  eval "NTree" (arbitrary :: Gen NTree)