packages feed

generic-random 0.3.0.0 → 0.4.0.0

raw patch · 8 files changed

+493/−262 lines, 8 filesdep +optparse-genericdep +testing-featdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: optparse-generic, testing-feat

Dependency ranges changed: base

API changes (from Hackage documentation)

- Generic.Random.Generic: genericArbitraryFrequency :: forall a. (Generic a, GA Unsized (Rep a)) => [Int] -> Gen a
- Generic.Random.Generic: genericArbitraryFrequency' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> [Int] -> Gen a
- Generic.Random.Internal.Generic: Freq :: ([Int] -> Gen a) -> Freq sized a
- Generic.Random.Internal.Generic: [unFreq] :: Freq sized a -> [Int] -> Gen a
- Generic.Random.Internal.Generic: baseCases' :: forall n f p. BaseCases n f => Tagged n [f p]
- Generic.Random.Internal.Generic: genericArbitraryFrequency :: forall a. (Generic a, GA Unsized (Rep a)) => [Int] -> Gen a
- Generic.Random.Internal.Generic: genericArbitraryFrequency' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> [Int] -> Gen a
- Generic.Random.Internal.Generic: instance (GHC.Generics.Generic c, Generic.Random.Internal.Generic.BaseCases n (GHC.Generics.Rep c)) => Generic.Random.Internal.Generic.BaseCases (Generic.Random.Internal.Generic.S n) (GHC.Generics.K1 i c)
- Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.BaseCases n f, Generic.Random.Internal.Generic.BaseCases n g) => Generic.Random.Internal.Generic.BaseCases n (f GHC.Generics.:*: g)
- Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.GA Generic.Random.Internal.Generic.Unsized f, Generic.Random.Internal.Generic.GA Generic.Random.Internal.Generic.Unsized g) => Generic.Random.Internal.Generic.GA Generic.Random.Internal.Generic.Unsized (f GHC.Generics.:*: g)
- Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.GAProduct f, Generic.Random.Internal.Generic.GAProduct g) => Generic.Random.Internal.Generic.GA (Generic.Random.Internal.Generic.Sized n) (f GHC.Generics.:*: g)
- Generic.Random.Internal.Generic: instance GHC.Base.Applicative (Generic.Random.Internal.Generic.Freq sized)
- Generic.Random.Internal.Generic: instance GHC.Base.Functor (Generic.Random.Internal.Generic.Freq sized)
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.BaseCases Generic.Random.Internal.Generic.Z (GHC.Generics.K1 i c)
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.BaseCases n GHC.Generics.U1
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.BaseCases n f => Generic.Random.Internal.Generic.BaseCases n (GHC.Generics.M1 i c f)
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GA Generic.Random.Internal.Generic.Unsized f => Generic.Random.Internal.Generic.GAProduct (GHC.Generics.M1 i c f)
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GA sized GHC.Generics.U1
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GA sized f => Generic.Random.Internal.Generic.GA sized (GHC.Generics.M1 i c f)
- Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GA sized f => Generic.Random.Internal.Generic.GASum sized (GHC.Generics.M1 i c f)
- Generic.Random.Internal.Generic: instance Test.QuickCheck.Arbitrary.Arbitrary c => Generic.Random.Internal.Generic.GA sized (GHC.Generics.K1 i c)
- Generic.Random.Internal.Generic: liftGen :: Gen a -> Freq sized a
- Generic.Random.Internal.Generic: newtype Freq sized a
+ Generic.Random.Generic: (%) :: WeightBuilder a => W (First a) -> Prec a r -> (a, Int, r)
+ Generic.Random.Generic: class ListBaseCases n f
+ Generic.Random.Generic: data W (c :: Symbol)
+ Generic.Random.Generic: data Weights a
+ Generic.Random.Generic: uniform :: UniformWeight (Weights_ (Rep a)) => Weights a
+ Generic.Random.Generic: weights :: (Weights_ (Rep a), Int, ()) -> Weights a
+ Generic.Random.Internal.Generic: (%) :: WeightBuilder a => W (First a) -> Prec a r -> (a, Int, r)
+ Generic.Random.Internal.Generic: L :: L
+ Generic.Random.Internal.Generic: N :: a -> Int -> b -> (:|) a b
+ Generic.Random.Internal.Generic: W :: Int -> W
+ Generic.Random.Internal.Generic: Weighted :: (Maybe (Int -> Gen a, Int)) -> Weighted a
+ Generic.Random.Internal.Generic: Weights :: (Weights_ (Rep a)) -> Int -> Weights a
+ Generic.Random.Internal.Generic: class ListBaseCases n f
+ Generic.Random.Internal.Generic: class UniformWeight a
+ Generic.Random.Internal.Generic: class WeightBuilder a where type Prec a r where {
+ Generic.Random.Internal.Generic: data (:|) a b
+ Generic.Random.Internal.Generic: data L (c :: Symbol)
+ Generic.Random.Internal.Generic: data Weights a
+ Generic.Random.Internal.Generic: gaSum' :: GASum sized f => Weights_ f -> Int -> Gen' sized (f p)
+ Generic.Random.Internal.Generic: instance (GHC.Generics.Generic c, Generic.Random.Internal.Generic.ListBaseCases n (GHC.Generics.Rep c)) => Generic.Random.Internal.Generic.ListBaseCases (Generic.Random.Internal.Generic.S n) (GHC.Generics.K1 i c)
+ Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.GAProduct f, GHC.TypeLits.KnownNat (Generic.Random.Internal.Generic.Arity f)) => Generic.Random.Internal.Generic.GA (Generic.Random.Internal.Generic.Sized n) (GHC.Generics.M1 GHC.Generics.C c f)
+ Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.ListBaseCases n f, Generic.Random.Internal.Generic.ListBaseCases n g) => Generic.Random.Internal.Generic.ListBaseCases n (f GHC.Generics.:*: g)
+ Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.ListBaseCases n f, Generic.Random.Internal.Generic.ListBaseCases n g) => Generic.Random.Internal.Generic.ListBaseCases n (f GHC.Generics.:+: g)
+ Generic.Random.Internal.Generic: instance (Generic.Random.Internal.Generic.UniformWeight a, Generic.Random.Internal.Generic.UniformWeight b) => Generic.Random.Internal.Generic.UniformWeight (a Generic.Random.Internal.Generic.:| b)
+ Generic.Random.Internal.Generic: instance GHC.Base.Alternative Generic.Random.Internal.Generic.Weighted
+ Generic.Random.Internal.Generic: instance GHC.Base.Applicative Generic.Random.Internal.Generic.Weighted
+ Generic.Random.Internal.Generic: instance GHC.Base.Functor (Generic.Random.Internal.Generic.Tagged a)
+ Generic.Random.Internal.Generic: instance GHC.Base.Functor Generic.Random.Internal.Generic.Weighted
+ Generic.Random.Internal.Generic: instance GHC.Base.Monad (Generic.Random.Internal.Generic.Gen' sized)
+ Generic.Random.Internal.Generic: instance GHC.Num.Num (Generic.Random.Internal.Generic.W c)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GA sized f => Generic.Random.Internal.Generic.GA sized (GHC.Generics.M1 GHC.Generics.D c f)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GAProduct GHC.Generics.U1
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GAProduct f => Generic.Random.Internal.Generic.GA Generic.Random.Internal.Generic.Unsized (GHC.Generics.M1 GHC.Generics.C c f)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GAProduct f => Generic.Random.Internal.Generic.GAProduct (GHC.Generics.M1 i c f)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.GAProduct f => Generic.Random.Internal.Generic.GASum sized (GHC.Generics.M1 i c f)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ListBaseCases Generic.Random.Internal.Generic.Z (GHC.Generics.K1 i c)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ListBaseCases n GHC.Generics.U1
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ListBaseCases n f => Generic.Random.Internal.Generic.BaseCases n (GHC.Generics.M1 i c f)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.ListBaseCases n f => Generic.Random.Internal.Generic.ListBaseCases n (GHC.Generics.M1 i c f)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.UniformWeight (Generic.Random.Internal.Generic.L c)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.WeightBuilder (Generic.Random.Internal.Generic.L c)
+ Generic.Random.Internal.Generic: instance Generic.Random.Internal.Generic.WeightBuilder a => Generic.Random.Internal.Generic.WeightBuilder (a Generic.Random.Internal.Generic.:| b)
+ Generic.Random.Internal.Generic: instance Test.QuickCheck.Arbitrary.Arbitrary c => Generic.Random.Internal.Generic.GAProduct (GHC.Generics.K1 i c)
+ Generic.Random.Internal.Generic: listBaseCases :: (ListBaseCases n f, Alternative u) => Tagged n (u (f p))
+ Generic.Random.Internal.Generic: newtype W (c :: Symbol)
+ Generic.Random.Internal.Generic: newtype Weighted a
+ Generic.Random.Internal.Generic: sized' :: (Int -> Gen' sized a) -> Gen' sized a
+ Generic.Random.Internal.Generic: type family Prec a r;
+ Generic.Random.Internal.Generic: uniform :: UniformWeight (Weights_ (Rep a)) => Weights a
+ Generic.Random.Internal.Generic: uniformWeight :: UniformWeight a => (a, Int)
+ Generic.Random.Internal.Generic: weights :: (Weights_ (Rep a), Int, ()) -> Weights a
+ Generic.Random.Internal.Generic: }
- Generic.Random.Generic: genericArbitrary :: forall a. (Generic a, GA Unsized (Rep a)) => Gen a
+ Generic.Random.Generic: genericArbitrary :: forall a. (Generic a, GA Unsized (Rep a)) => Weights a -> Gen a
- Generic.Random.Generic: genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> Gen a
+ Generic.Random.Generic: genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> Weights a -> Gen a
- Generic.Random.Generic: type BaseCases' n a = (Generic a, BaseCases n (Rep a))
+ Generic.Random.Generic: type BaseCases' n a = (Generic a, ListBaseCases n (Rep a))
- Generic.Random.Internal.Generic: baseCases :: BaseCases n f => Tagged n [[f p]]
+ Generic.Random.Internal.Generic: baseCases :: BaseCases n f => Weights_ f -> Int -> Tagged n (Weighted (f p))
- Generic.Random.Internal.Generic: gArbitrarySingle :: forall sized f p. GA sized f => Gen' sized (f p)
+ Generic.Random.Internal.Generic: gArbitrarySingle :: forall sized f p c0. (GA sized f, Weights_ f ~ L c0) => Gen' sized (f p)
- Generic.Random.Internal.Generic: ga :: GA sized f => Freq sized (f p)
+ Generic.Random.Internal.Generic: ga :: GA sized f => Weights_ f -> Int -> Gen' sized (f p)
- Generic.Random.Internal.Generic: gaProduct :: GAProduct f => (Int, Gen' Unsized (f p))
+ Generic.Random.Internal.Generic: gaProduct :: GAProduct f => Gen (f p)
- Generic.Random.Internal.Generic: gaSum :: GASum sized f => [Gen' sized (f p)]
+ Generic.Random.Internal.Generic: gaSum :: GASum sized f => Int -> Weights_ f -> Gen' sized (f p)
- Generic.Random.Internal.Generic: genericArbitrary :: forall a. (Generic a, GA Unsized (Rep a)) => Gen a
+ Generic.Random.Internal.Generic: genericArbitrary :: forall a. (Generic a, GA Unsized (Rep a)) => Weights a -> Gen a
- Generic.Random.Internal.Generic: genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> Gen a
+ Generic.Random.Internal.Generic: genericArbitrary' :: forall n a. (Generic a, GA (Sized n) (Rep a)) => n -> Weights a -> Gen a
- Generic.Random.Internal.Generic: type BaseCases' n a = (Generic a, BaseCases n (Rep a))
+ Generic.Random.Internal.Generic: type BaseCases' n a = (Generic a, ListBaseCases n (Rep a))

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+# 0.4.0.0++- Check well-formedness of constructor distributions at compile time.+- No longer support GHC 7.10.3 (the above feature relies on Generic+  information which does not exist before GHC 8)+ # 0.3.0.0  - Support GHC 7.10.3
README.md view
@@ -1,4 +1,4 @@-Generic random generators [![Hackage](https://img.shields.io/hackage/v/generic-random.svg)](https://hackage.haskell.org/package/generic-random) [![Build Status](https://travis-ci.org/Lysxia/generic-random.svg)](https://travis-ci.org/Lysxia/generic-random.svg?branch=master)+Generic random generators [![Hackage](https://img.shields.io/hackage/v/generic-random.svg)](https://hackage.haskell.org/package/generic-random) [![Build Status](https://travis-ci.org/Lysxia/generic-random.svg)](https://travis-ci.org/Lysxia/generic-random) =========================  `Generic.Random.Data`@@ -50,7 +50,7 @@       deriving (Show, Generic)      instance Arbitrary a => Arbitrary (Tree a) where-      arbitrary = genericArbitrary' Z+      arbitrary = genericArbitrary' Z uniform      -- Equivalent to     -- > arbitrary =@@ -66,7 +66,7 @@     main = sample (arbitrary :: Gen (Tree ())) ``` -- User-specified distribution of constructors.+- User-specified distribution of constructors, with compile-time checks. - A simple (optional) strategy to ensure termination: `Test.QuickCheck.Gen`'s   size parameter decreases at every recursive `genericArbitrary'` call; when it   reaches zero, sample directly from a finite set of finite values.
bench/binaryTree.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}+{-# LANGUAGE DeriveDataTypeable, DeriveGeneric, TemplateHaskell #-} module Main where  import Control.Applicative@@ -10,6 +10,7 @@ import GHC.Generics import Control.DeepSeq import Criterion.Main+import Test.Feat import Test.QuickCheck import Test.QuickCheck.Gen import Test.QuickCheck.Random@@ -19,10 +20,16 @@ import Generic.Random.Internal.Types  data T = N T T | L-  deriving (Eq, Ord, Show, Data, Generic)+  deriving (Eq, Ord, Show, Data, Typeable, Generic)  instance NFData T +deriveEnumerable ''T++size :: Num a => T -> a+size L = 1+size (N l r) = 1 + size l + size r+ gen1 :: Int -> Gen T gen1 n = runRejectT (tolerance epsilon (n + 1)) gen'   where@@ -39,19 +46,17 @@         (k (n+1) L)         (gen' (n+1) $ \m l -> gen' m $ \m r -> k m (N l r)) -main = getGs >>= \gs -> defaultMain $ liftA2 (\n f -> f n gs)-  [4 ^ e | e <- [1 .. 5]]+genFeat :: Int -> Gen T+genFeat = uniform +main = newQCGen >>= \g -> defaultMain $ liftA2 (\n f -> f n g)+  [4 ^ e | e <- [1 .. 6]]+   -- Singular rejection sampling   [ bg "handwritten1" gen1   , bg "handwritten2" gen2-  , bg "SR" generatorSR -  -- Sized rejection sampling-  , bg "R" generatorR'--  -- Sized rejection sampling, not memoizing oracle-  , bg' "R-recomp" generatorR'+  , bg "feat" genFeat    -- Pointed generator   , bg "P" generatorP'@@ -59,20 +64,33 @@   -- Pointed generator with rejection sampling   , bg "PR" generatorPR' +  , bg "SR" generatorSR++  -- Sized rejection sampling+  , bg "R" generatorR'++  -- Sized rejection sampling, not memoizing oracle+  , bg' "R-recomp" generatorR'+   -- Pointed generator, not memoizing oracle   , bg' "P-recomp" generatorP'   ] -bg, bg' :: String -> (Int -> Gen T) -> Int -> [QCGen] -> Benchmark-bg name gen n gs =-  bench (name ++ "_" ++ show n) $-    nf (fmap (\g -> unGen gg g 0)) gs+bg, bg' :: String -> (Int -> Gen T) -> Int -> QCGen -> Benchmark+bg name gen n g =+  bench (name ++ "_" ++ show n) $ nf f g   where+    go 0 = return (0 :: Int)+    go k = liftA2 (\t s -> size t + s) gg (go (k-1))     gg = gen n+    f g = unGen (go 100) g 0 -bg' name gen n gs =-  bench (name ++ "_" ++ show n) $-    nf (fmap (\(n, g) -> unGen (gen n) g 0)) (fmap ((,) n) gs)+bg' name gen n g =+  bench (name ++ "_" ++ show n) $ nf f (n, g)+  where+    go n 0 = return (0 :: Int)+    go n k = liftA2 (\t s -> size t + s) (gen n) (go n (k-1))+    f (n, g) = unGen (go n 100) g 0 -getGs :: IO [QCGen]-getGs = replicateM 100 newQCGen+avgSize :: [T] -> Double+avgSize ts = sum (fmap size ts) / fromIntegral (length ts)
generic-random.cabal view
@@ -1,5 +1,5 @@ name:                generic-random-version:             0.3.0.0+version:             0.4.0.0 synopsis:            Generic random generators description:         Please see the README. homepage:            http://github.com/lysxia/generic-random@@ -12,8 +12,15 @@ build-type:          Simple extra-source-files:  README.md CHANGELOG.md cabal-version:       >=1.10-tested-with:         GHC == 7.10.3, GHC == 8.0.1+tested-with:         GHC == 8.0.1 +flag test+  Description:+    Enable testing. Disabled by default because the current test suite+    is slow and can fail with non-zero probability.+  Manual:  True+  Default: False+ library   hs-source-dirs:      src   exposed-modules:@@ -27,7 +34,7 @@     Generic.Random.Internal.Solver     Generic.Random.Internal.Types   build-depends:-    base >= 4.8 && < 5,+    base >= 4.9 && < 4.10,     containers,     hashable,     unordered-containers,@@ -47,26 +54,35 @@   hs-source-dirs:   test   main-is:          tree.hs   default-language: Haskell2010-  build-depends:-    base,-    QuickCheck,-    generic-random   other-modules:     Test.Stats,     Test.Tree+  if flag(test)+    build-depends:+      base,+      QuickCheck,+      optparse-generic,+      generic-random+  else+    buildable: False  benchmark bench-binarytree   type:             exitcode-stdio-1.0   hs-source-dirs:   bench   main-is:          binaryTree.hs   default-language: Haskell2010-  build-depends:-    base,-    criterion,-    deepseq,-    QuickCheck,-    transformers,-    generic-random+  ghc-options: -O2+  if flag(test)+    build-depends:+      base,+      criterion,+      deepseq,+      QuickCheck,+      transformers,+      testing-feat,+      generic-random+  else+    buildable: False  source-repository head   type:     git
src/Generic/Random/Generic.hs view
@@ -2,34 +2,213 @@ -- -- Here is an example. Define your type. ----- > data Tree a = Leaf a | Node (Tree a) (Tree a)--- >   deriving Generic+-- @+-- data Tree a = Leaf a | Node (Tree a) (Tree a)+--   deriving Generic+-- @ ----- Pick an arbitrary implementation.+-- Pick an 'arbitrary' implementation. ----- > instance Arbitrary a => Arbitrary (Tree a) where--- >   arbitrary = genericArbitraryFrequency [9, 8]+-- @+-- instance Arbitrary a => Arbitrary (Tree a) where+--   arbitrary = 'genericArbitrary' ('weights' (9 '%' 8 '%' ()))+-- @ -- -- @arbitrary :: 'Gen' (Tree a)@ picks a @Leaf@ with probability 9\/17, or a -- @Node@ with probability 8\/17, and recursively fills their fields with -- @arbitrary@.+--+-- == Distribution of constructors+--+-- The distribution of constructors can be specified using 'weights' applied to+-- a special list of /weights/ in the same order as the data type definition.+-- This assigns to each constructor a probability proportional to its weight;+-- in other words, @p_C = weight_C / sumOfWeights@.+--+-- The list of weights is built up with the @('%')@ operator as a cons, and using+-- the unit @()@ as the empty list, in the order corresponding to the data type+-- definition.+--+-- For @Tree@, 'genericArbitrary' produces code equivalent to the following:+--+-- @+-- 'genericArbitrary' :: Arbitrary a => 'Weights' (Tree a) -> Gen (Tree a)+-- 'genericArbitrary' ('weighted' (x '%' y '%' ())) =+--   frequency+--     [ (x, Leaf \<$\> arbitrary)+--     , (y, Node \<$\> arbitrary \<*\> arbitrary)+--     ]+-- @+--+-- The weights actually have type @'W' \"ConstructorName\"@ (just a newtype+-- around 'Int'), so that you can annotate a weight with its corresponding+-- constructor, and it will be checked that you got the order right.+--+-- This will type-check.+--+-- @+-- 'weighted' ((x :: 'W' \"Leaf\") '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a)+-- 'weighted' (x '%' (y :: 'W' \"Node\") '%' ()) :: 'Weights' (Tree a)+-- @+--+-- This will not: the first requires an order of constructors different from+-- the definition of the @Tree@ type; the second doesn't have the right number+-- of weights.+--+-- @+-- 'weighted' ((x :: 'W' \"Node\") '%' y '%' ()) :: 'Weights' (Tree a)+-- 'weighted' (x '%' y '%' z '%' ()) :: 'Weights' (Tree a)+-- @+--+-- === Uniform distribution+--+-- You can specify the uniform distribution with 'uniform'.+--+-- For @Tree@, @'genericArbitrary' 'uniform'@ produces code equivalent to the+-- following:+--+-- @+-- 'genericArbitrary' 'uniform' :: Arbitrary a => Gen (Tree a)+-- 'genericArbitrary' 'uniform' =+--   oneof+--     [ Leaf \<$\> arbitrary                -- Uses Arbitrary a+--     , Node \<$\> arbitrary \<*\> arbitrary  -- Uses Arbitrary (Tree a)+--     ]+-- @+--+-- Note that for many types, a uniform distribution tends to produce big+-- values. For instance for @Tree a@, generated values are finite but the+-- __average__ number of @Leaf@ and @Node@ constructors is __infinite__.+--+-- == Ensuring termination+--+-- As was just mentioned, one must be careful with recursive types+-- to avoid producing extremely large values.+--+-- The alternative '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 finite term whenever it can find any of the given type.  This+-- generally ensures that the number of constructors remains close to the+-- initial size parameter passed to 'Gen'.+--+-- A natural number @n@ determines the maximum /depth/ of terms that can be+-- used to end recursion.+-- It is encoded using @'Z' :: 'Z'@ and @'S' :: n -> 'S' n@.+--+-- @+-- 'genericArbitrary'' n ('weights' (...))+-- @+--+-- With @n = 'Z'@, the generator looks for a simple nullary constructor.  If none+-- exist at the current type, as is the case for our @Tree@ type, it carries on+-- as in 'genericArbitrary'.+--+-- @+-- 'genericArbitrary'' 'Z' :: Arbitrary a => 'Weights' (Tree a) -> Gen (Tree a)+-- 'genericArbitrary'' 'Z' ('weights' (x '%' y '%' ())) =+--   frequency+--     [ (x, Leaf \<$\> arbitrary)+--     , (y, scale (\`div\` 2) $ Node \<$\> arbitrary \<*\> arbitrary)+--     -- 2 because Node is 2-ary.+--     ]+-- @+--+-- Here is another example with nullary constructors:+--+-- @+-- data Tree' = Leaf1 | Leaf2 | Node3 Tree' Tree' Tree'+--   deriving Generic+--+-- instance Arbitrary Tree' where+--   arbitrary = 'genericArbitrary'' 'Z' ('weights' (1 '%' 2 '%' 3 '%' ()))+-- @+--+-- Here, @'genericArbitrary'' 'Z'@ is equivalent to:+--+-- @+-- 'genericArbitrary'' 'Z' :: 'Weights' Tree' -> Gen Tree'+-- 'genericArbitrary'' 'Z' ('weights' (x '%' y '%' z '%' ())) =+--   sized $ \n ->+--     if n == 0 then+--       -- If the size parameter is zero, the non-nullary alternative is discarded.+--       frequency $+--         [ (x, return Leaf1)+--         , (y, return 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+-- @+--+-- To increase the chances of termination when no nullary constructor is directly+-- available, such as in @Tree@, we can pass a larger depth @n@. The effectiveness+-- of this parameter depends on the concrete type the generator is used for.+--+-- For instance, if we want to generate a value of type @Tree ()@, there is a+-- value of depth 1 (represented by @'S' 'Z'@) that we can use to end+-- recursion: @Leaf ()@.+--+-- @+-- 'genericArbitrary'' ('S' 'Z') :: 'Weights' (Tree ()) -> Gen (Tree ())+-- 'genericArbitrary'' ('S' 'Z') ('weights' (x '%' y '%' ())) =+--   sized $ \n ->+--     if n == 0 then+--       return (Leaf ())+--     else+--       frequency+--         [ (x, Leaf \<$\> arbitrary)+--         , (y, scale (\`div\` 2) $ Node \<$\> arbitrary \<*\> arbitrary)+--         ]+-- @+--+-- 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.+--+-- @UndecidableInstances@ is also required.+--+-- @+-- instance (Arbitrary a, Generic a, 'ListBaseCases' 'Z' (Rep a))+--   => Arbitrary (Tree a) where+--   arbitrary = 'genericArbitrary'' ('S' 'Z') ('weights' (1 '%' 2 '%' ()))+-- @+--+-- A synonym is provided for brevity.+--+-- @+-- instance (Arbitrary a, 'BaseCases'' Z a) => Arbitrary (Tree a) where+--   arbitrary = 'genericArbitrary'' ('S' 'Z') ('weights' (1 '%' 2 '%' ()))+-- @ + module Generic.Random.Generic   (     -- * Arbitrary implementations     genericArbitrary-  , genericArbitraryFrequency-  , genericArbitraryFrequency'   , genericArbitrary' +    -- * Specifying finite distributions+  , Weights+  , W+  , weights+  , (%)+  , uniform+     -- * Type-level natural numbers     -- $nat   , Z (..)   , S (..) -    -- * Generic class for finite values+    -- * Generic classes for finite values   , BaseCases'   , BaseCases+  , ListBaseCases   ) where  import Generic.Random.Internal.Generic
src/Generic/Random/Internal/Generic.hs view
@@ -1,259 +1,212 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE DeriveFunctor, GeneralizedNewtypeDeriving #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+ module Generic.Random.Internal.Generic where  import Control.Applicative import Data.Coerce+import GHC.Exts (Proxy#, proxy#) import GHC.Generics hiding ( S )+import GHC.TypeLits import Test.QuickCheck  -- * Random generators --- | Pick a constructor with uniform probability, and fill its fields+-- | Pick a constructor with a given distribution, and fill its fields -- recursively.------ An equivalent definition for @Tree@ is:------ > genericArbitrary :: Arbitrary a => Gen (Tree a)--- > genericArbitrary =--- >   oneof--- >     [ Leaf <$> arbitrary                -- Uses Arbitrary a--- >     , Node <$> arbitrary <*> arbitrary  -- Uses Arbitrary (Tree a)--- >     ]------ Note that for many types, 'genericArbitrary' tends to produce big values.--- For instance for @Tree a@ values are finite but the average number of--- @Leaf@ and @Node@ constructors is infinite.+genericArbitrary+  :: forall a+  .  (Generic a, GA Unsized (Rep a))+  => Weights a+  -> Gen a+genericArbitrary (Weights w n) = (unGen' . fmap to) (ga w n :: Gen' Unsized (Rep a p)) -genericArbitrary :: forall a. (Generic a, GA Unsized (Rep a)) => Gen a-genericArbitrary =-  (($ repeat 1) . unFreq . fmap to) (ga :: Freq Unsized (Rep a p))+-- | Like 'genericArbitrary'', with bounded size to ensure termination for+-- recursive types.+genericArbitrary'+  :: forall n a+  . (Generic a, GA (Sized n) (Rep a))+  => n+  -> Weights a  -- ^ List of weights for every constructor+  -> Gen a+genericArbitrary' _ (Weights w n) =+  (unGen' . fmap to) (ga w n :: Gen' (Sized n) (Rep a p))  --- | This allows to specify the probability distribution of constructors--- as a list of weights, in the same order as the data type definition.------ An equivalent definition for @Tree@ is:------ > genericArbitraryFrequency :: Arbitrary a => [Int] -> Gen (Tree a)--- > genericArbitraryFrequency [x, y] =--- >   frequency--- >     [ (x, Leaf <$> arbitrary)--- >     , (y, Node <$> arbitrary <*> arbitrary)--- >     ]+-- * Internal -genericArbitraryFrequency-  :: forall a. (Generic a, GA Unsized (Rep a))-  => [Int]  -- ^ List of weights for every constructor-  -> Gen a-genericArbitraryFrequency = (unFreq . fmap to) (ga :: Freq Unsized (Rep a p))+type family Weights_ (f :: * -> *) :: * where+  Weights_ (f :+: g) = Weights_ f :| Weights_ g+  Weights_ (M1 D _c f) = Weights_ f+  Weights_ (M1 C ('MetaCons c _i _j) _f) = L c +data a :| b = N a Int b+data L (c :: Symbol) = L --- | The size parameter of 'Gen' is divided among the fields of the chosen--- constructor.  When it reaches zero, the generator selects a finite term--- whenever it can find any of the given type.------ The natural number @n@ determines the maximum /depth/ of terms that can be--- used to end recursion.--- It is encoded using @'Z' :: 'Z'@ and @'S' :: n -> 'S' n@.------ > genericArbitraryFrequency' n weights------ With @n = 'Z'@, the generator looks for a simple nullary constructor.  If none--- exist at the current type, as is the case for our @Tree@ type, it carries on--- as in 'genericArbitraryFrequency'.------ > genericArbitraryFrequency' Z :: Arbitrary a => [Int] -> Gen (Tree a)--- > genericArbitraryFrequency' Z [x, y] =--- >   frequency--- >     [ (x, Leaf <$> arbitrary)--- >     , (y, scale (`div` 2) $ Node <$> arbitrary <*> arbitrary)--- >     ]--- >     -- 2 because Node is 2-ary.------ Here is another example:------ > data Tree' = Leaf1 | Leaf2 | Node3 Tree' Tree' Tree'--- >   deriving Generic--- >--- > instance Arbitrary Tree' where--- >   arbitrary = genericArbitraryFrequency' Z [1, 2, 3]------ 'genericArbitraryFrequency'' is equivalent to:------ > genericArbitraryFrequency' Z :: [Int] -> Gen Tree'--- > genericArbitraryFrequency' Z [x, y, z] =--- >   sized $ \n ->--- >     if n == 0 then--- >       -- If the size parameter is zero, the non-nullary alternative is discarded.--- >       frequency $--- >         [ (x, return Leaf1)--- >         , (y, return 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------ To increase the chances of termination when no nullary constructor is directly--- available, such as in @Tree@, we can pass a larger depth @n@. The effectiveness--- of this parameter depends on the concrete type the generator is used for.------ For instance, if we want to generate a value of type @Tree ()@, there is a--- value of depth 1 (represented by @'S' 'Z'@) that we can use to end--- recursion: @Leaf ()@.------ > genericArbitraryFrequency' (S Z) :: [Int] -> Gen (Tree ())--- > genericArbitraryFrequency' (S Z) [x, y] =--- >   sized $ \n ->--- >     if n == 0 then--- >       return (Leaf ())--- >     else--- >       frequency--- >         [ (x, Leaf <$> arbitrary)--- >         , (y, scale (`div` 2) $ Node <$> arbitrary <*> arbitrary)--- >         ]+-- | Trees of weights assigned to constructors of type @a@,+-- rescaled to obtain a probability distribution. ----- 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.+-- Two ways of constructing them. ----- @FlexibleContexts@ and @UndecidableInstances@ are also required.+-- @+-- 'weights' (x1 '%' x2 '%' ... '%' xn '%' ()) :: 'Weights' a+-- 'uniform' :: 'Weights' a+-- @ ----- > instance (Arbitrary a, Generic a, BaseCases Z (Rep a))--- >   => Arbitrary (Tree a) where--- >   arbitrary = genericArbitraryFrequency' (S Z) [1, 2]+-- Using @weights@, there must be exactly as many weights as+-- there are constructors. ----- A synonym is provided for brevity.+-- 'uniform' is equivalent to @'weights' (1 '%' ... '%' 1 '%' ())@+-- (automatically fills out the right number of 1s).+data Weights a = Weights (Weights_ (Rep a)) Int++-- | Type of a single weight, tagged with the name of the associated+-- constructor for additional compile-time checking. ----- > instance (Arbitrary a, BaseCases' Z a) => Arbitrary (Tree a) where--- >   arbitrary = genericArbitraryFrequency' (S Z) [1, 2]+-- @+-- 'weights' ((9 :: 'W' \"Leaf\") '%' (8 :: 'W' \"Node\") '%' ())+-- @+newtype W (c :: Symbol) = W Int deriving Num -genericArbitraryFrequency'-  :: forall n a-  . (Generic a, GA (Sized n) (Rep a))-  => n-  -> [Int]  -- ^ List of weights for every constructor-  -> Gen a-genericArbitraryFrequency' _ =-  (unFreq . fmap to) (ga :: Freq (Sized n) (Rep a p))+-- | A smart constructor to specify a custom distribution.+weights :: (Weights_ (Rep a), Int, ()) -> Weights a+weights (w, n, ()) = Weights w n +-- | Uniform distribution.+uniform :: UniformWeight (Weights_ (Rep a)) => Weights a+uniform =+  let (w, n) = uniformWeight+  in Weights w n --- | Like 'genericArbitraryFrequency'', but with uniformly distributed--- constructors.+type family First a :: Symbol where+  First (a :| _b) = First a+  First (L c) = c -genericArbitrary'-  :: forall n a-  . (Generic a, GA (Sized n) (Rep a)) => n -> Gen a-genericArbitrary' _ =-  (($ repeat 1) . unFreq . fmap to) (ga :: Freq (Sized n) (Rep a p))+class WeightBuilder a where+  type Prec a r +  -- | A binary constructor for building up trees of weights.+  (%) :: W (First a) -> Prec a r -> (a, Int, r) --- * Internal+infixr 1 % -newtype Freq sized a = Freq { unFreq :: [Int] -> Gen a }-  deriving Functor+instance WeightBuilder a => WeightBuilder (a :| b) where+  type Prec (a :| b) r = Prec a (b, Int, r)+  m % prec =+    let (a, n, (b, p, r)) = m % prec+    in (N a n b, n + p, r) -instance Applicative (Freq sized) where-  pure = Freq . pure . pure-  Freq f <*> Freq x = Freq (liftA2 (<*>) f x)+instance WeightBuilder (L c) where+  type Prec (L c) r = r+  W m % prec = (L, m, prec) +class UniformWeight a where+  uniformWeight :: (a, Int)++instance (UniformWeight a, UniformWeight b) => UniformWeight (a :| b) where+  uniformWeight =+    let+      (a, m) = uniformWeight+      (b, n) = uniformWeight+    in+      (N a m b, m + n)++instance UniformWeight (L c) where+  uniformWeight = (L, 1)+ newtype Gen' sized a = Gen' { unGen' :: Gen a }-  deriving (Functor, Applicative)+  deriving (Functor, Applicative, Monad)  data Sized n data Unsized -liftGen :: Gen a -> Freq sized a-liftGen = Freq . const+sized' :: (Int -> Gen' sized a) -> Gen' sized a+sized' g = Gen' . sized $ \sz -> unGen' (g sz)  -- | Generic Arbitrary class GA sized f where-  ga :: Freq sized (f p)+  ga :: Weights_ f -> Int -> Gen' sized (f p) -instance GA sized U1 where-  ga = pure U1+instance GA sized f => GA sized (M1 D c f) where+  ga w n = fmap M1 (ga w n) -instance Arbitrary c => GA sized (K1 i c) where-  ga = liftGen . fmap K1 $ arbitrary+instance GAProduct f => GA Unsized (M1 C c f) where+  ga _ _ = (Gen' . fmap M1) gaProduct -instance GA sized f => GA sized (M1 i c f) where-  ga = fmap M1 ga+instance (GAProduct f, KnownNat (Arity f)) => GA (Sized n) (M1 C c f) where+  ga _ _ = Gen' (scale (`div` arity) gaProduct)+    where+      arity = fromInteger (natVal' (proxy# :: Proxy# (Arity f)))  instance (GASum (Sized n) f, GASum (Sized n) g, BaseCases n f, BaseCases n g)   => GA (Sized n) (f :+: g) where-  ga = frequency' gaSum baseCases-    where-      frequency' :: [Gen' sized a] -> Tagged n [[a]] -> Freq sized a-      frequency' as (Tagged a0s) = Freq $ \ws ->-        let-          units = [(w, elements a0) | (w, a0@(_ : _)) <- zip ws a0s]-        in-          sized $ \sz -> frequency $-            if sz == 0 && not (null units) then-              units-            else-              [(w, a) | (w, Gen' a) <- zip ws as]+  ga w n = sized' $ \sz ->+    case unTagged (baseCases w n :: Tagged n (Weighted ((f :+: g) p))) of+      Weighted (Just (bc, n)) | sz == 0 -> Gen' (choose (0, n - 1) >>= bc)+      _ -> gaSum' w n  instance (GASum Unsized f, GASum Unsized g) => GA Unsized (f :+: g) where-  ga = frequency' gaSum-    where-      frequency' :: [Gen' sized a] -> Freq sized a-      frequency' as = Freq $ \ws -> frequency-        [(w, a) | (w, Gen' a) <- zip ws as]--instance (GA Unsized f, GA Unsized g) => GA Unsized (f :*: g) where-  ga = liftA2 (:*:) ga ga--instance (GAProduct f, GAProduct g) => GA (Sized n) (f :*: g) where-  ga = constScale' a-    where-      constScale' :: Gen' Unsized a -> Freq (Sized n) a-      constScale' = Freq . const . scale (`div` arity) . unGen'-      (arity, a) = gaProduct-+  ga = gaSum' -gArbitrarySingle :: forall sized f p . GA sized f => Gen' sized (f p)-gArbitrarySingle = Gen' (unFreq (ga :: Freq sized (f p)) [1])+gArbitrarySingle+  :: forall sized f p c0+  .  (GA sized f, Weights_ f ~ L c0)+  => Gen' sized (f p)+gArbitrarySingle = ga L 0 +gaSum' :: GASum sized f => Weights_ f -> Int -> Gen' sized (f p)+gaSum' w n = do+  i <- Gen' $ choose (0, n-1)+  gaSum i w  class GASum sized f where-  gaSum :: [Gen' sized (f p)]+  gaSum :: Int -> Weights_ f -> Gen' sized (f p)  instance (GASum sized f, GASum sized g) => GASum sized (f :+: g) where-  gaSum = (fmap . fmap) L1 gaSum ++ (fmap . fmap) R1 gaSum+  gaSum i (N a n b)+    | i < n = fmap L1 (gaSum i a)+    | otherwise = fmap R1 (gaSum (i - n) b) -instance GA sized f => GASum sized (M1 i c f) where-  gaSum = [gArbitrarySingle]+instance GAProduct f => GASum sized (M1 i c f) where+  gaSum _ _ = Gen' gaProduct   class GAProduct f where-  gaProduct :: (Int, Gen' Unsized (f p))+  gaProduct :: Gen (f p) -instance GA Unsized f => GAProduct (M1 i c f) where-  gaProduct = (1, gArbitrarySingle)+instance GAProduct U1 where+  gaProduct = pure U1 +instance Arbitrary c => GAProduct (K1 i c) where+  gaProduct = fmap K1 arbitrary++instance GAProduct f => GAProduct (M1 i c f) where+  gaProduct = fmap M1 gaProduct+ instance (GAProduct f, GAProduct g) => GAProduct (f :*: g) where-  gaProduct = (m + n, liftA2 (:*:) a b)-    where-      (m, a) = gaProduct-      (n, b) = gaProduct+  gaProduct = liftA2 (:*:) gaProduct gaProduct +type family Arity f :: Nat where+  Arity (f :*: g) = Arity f + Arity g+  Arity (M1 _i _c _f) = 1 + newtype Tagged a b = Tagged { unTagged :: b }+  deriving Functor  -- $nat -- Use the 'Z' and 'S' data types to define the depths of values used--- by 'genericArbitraryFrequency'' and 'genericArbitrary'' to make--- generators terminate.+-- by 'genericArbitrary'' to make generators terminate.  -- | Zero data Z = Z@@ -261,38 +214,87 @@ -- | Successor data S n = S n --- | A @BaseCases n ('Rep' a)@ constraint basically provides the list of values--- of type @a@ with depth at most @n@.+newtype Weighted a = Weighted (Maybe (Int -> Gen a, Int))+  deriving Functor++instance Applicative Weighted where+  pure a = Weighted (Just ((pure . pure) a, 1))+  Weighted f <*> Weighted a = Weighted $ liftA2 g f a+    where+      g (f, m) (a, n) =+        ( \i ->+            let (j, k) = i `divMod` m+            in f j <*> a k+        , m * n )++instance Alternative Weighted where+  empty = Weighted Nothing+  a <|> Weighted Nothing = a+  Weighted Nothing <|> b = b+  Weighted (Just (a, m)) <|> Weighted (Just (b, n)) = Weighted . Just $+    ( \i ->+        if i < m then+          a i+        else+          b (i - m)+    , m + n )+ class BaseCases n f where-  baseCases :: Tagged n [[f p]]+  baseCases :: Weights_ f -> Int -> Tagged n (Weighted (f p)) --- | For convenience.-type BaseCases' n a = (Generic a, BaseCases n (Rep a))+instance (BaseCases n f, BaseCases n g) => BaseCases n (f :+: g) where+  baseCases (N a m b) n =+    concat+      ((fmap . fmap) L1 (baseCases a m))+      ((fmap . fmap) R1 (baseCases b (n - m)))+    where+      concat :: Alternative u => Tagged n (u a) -> Tagged n (u a) -> Tagged n (u a)+      concat (Tagged a) (Tagged b) = Tagged (a <|> b) -baseCases' :: forall n f p. BaseCases n f => Tagged n [f p]-baseCases' = (Tagged . concat . unTagged) (baseCases :: Tagged n [[f p]])+instance ListBaseCases n f => BaseCases n (M1 i c f) where+  baseCases _ n = fmap reweigh listBaseCases+    where+      reweigh :: Weighted a -> Weighted a+      reweigh (Weighted h) = Weighted (fmap (\(g, _) -> (g, n)) h) -instance BaseCases n U1 where-  baseCases = Tagged [[U1]]+-- | A @ListBaseCases n ('Rep' a)@ constraint basically provides the list of+-- values of type @a@ with depth at most @n@.+class ListBaseCases n f where+  listBaseCases :: Alternative u => Tagged n (u (f p)) -instance BaseCases n f => BaseCases n (M1 i c f) where-  baseCases = (coerce :: Tagged n [[f p]] -> Tagged n [[M1 i c f p]]) baseCases+-- | For convenience.+type BaseCases' n a = (Generic a, ListBaseCases n (Rep a)) -instance BaseCases Z (K1 i c) where-  baseCases = Tagged [[]]+instance ListBaseCases n U1 where+  listBaseCases = Tagged (pure U1) -instance (Generic c, BaseCases n (Rep c)) => BaseCases (S n) (K1 i c) where-  baseCases =-    (Tagged . (fmap . fmap) (K1 . to) . unTagged)-      (baseCases :: Tagged n [[Rep c p]])+instance ListBaseCases n f => ListBaseCases n (M1 i c f) where+  listBaseCases = (fmap . fmap) M1 listBaseCases -instance (BaseCases n f, BaseCases n g) => BaseCases n (f :+: g) where-  baseCases = Tagged $-    ((fmap . fmap) L1 . unTagged) (baseCases :: Tagged n [[f p]]) ++-    ((fmap . fmap) R1 . unTagged) (baseCases :: Tagged n [[g p]])+instance ListBaseCases Z (K1 i c) where+  listBaseCases = Tagged empty -instance (BaseCases n f, BaseCases n g) => BaseCases n (f :*: g) where-  baseCases = Tagged-    [ liftA2 (:*:)-        (unTagged (baseCases' :: Tagged n [f p]))-        (unTagged (baseCases' :: Tagged n [g p])) ]+instance (Generic c, ListBaseCases n (Rep c)) => ListBaseCases (S n) (K1 i c) where+  listBaseCases = (retag . (fmap . fmap) (K1 . to)) listBaseCases+    where+      retag :: Tagged n a -> Tagged (S n) a+      retag = coerce++instance (ListBaseCases n f, ListBaseCases n g) => ListBaseCases n (f :+: g) where+  listBaseCases =+    concat+      ((fmap . fmap) L1 listBaseCases)+      ((fmap . fmap) R1 listBaseCases)+    where+      concat :: Alternative u => Tagged n (u a) -> Tagged n (u a) -> Tagged n (u a)+      concat (Tagged a) (Tagged b) = Tagged (a <|> b)++instance (ListBaseCases n f, ListBaseCases n g) => ListBaseCases n (f :*: g) where+  listBaseCases = liftedP listBaseCases listBaseCases+    where+      liftedP+        :: Applicative u+        => Tagged n (u (f p))+        -> Tagged n (u (g p))+        -> Tagged n (u ((f :*: g) p))+      liftedP (Tagged f) (Tagged g) = Tagged (liftA2 (:*:) f g)
test/Test/Tree.hs view
@@ -16,4 +16,4 @@ size L = 0  instance Arbitrary T where-  arbitrary = genericArbitraryFrequency [9, 8]+  arbitrary = genericArbitrary (weights (9 % 8 % ()))
test/tree.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+ import Control.Monad import Data.Data import Data.Foldable@@ -6,6 +10,8 @@ import System.Exit import System.IO +import Options.Generic+ import Generic.Random.Data import Generic.Random.Internal.Data @@ -23,10 +29,14 @@     when (x `mod` 1000 == 0) $ putStr "." >> hFlush stdout   gen +-- | Invocation: stack test [--test-arguments TEST_SIZE]+type Input = Maybe (Int <?> "Test size")+ main = do+  n_ <- getRecord "Test program" :: IO Input   success <- newIORef True -  let n = 64+  let n = maybe 10 unHelpful n_       range = tolerance epsilon n    for_