33module Test.QuickCheck.Gen
44 ( Gen ()
55 , GenState ()
6- , GenOut ()
76 , Size ()
87 , repeatable
98 , stateful
@@ -16,6 +15,7 @@ module Test.QuickCheck.Gen
1615 , frequency
1716 , arrayOf
1817 , arrayOf1
18+ , listOf
1919 , vectorOf
2020 , elements
2121 , runGen
@@ -31,14 +31,19 @@ import Prelude
3131
3232import Control.Monad.Eff (Eff ())
3333import Control.Monad.Eff.Random (RANDOM ())
34+ import Control.Monad.State (State (..), runState , evalState )
35+ import Control.Monad.State.Class (state , modify )
36+ import Control.Monad.Rec.Class (MonadRec , tailRecM )
3437import Data.Array ((!!), length , range )
38+ import Data.Tuple (Tuple (..))
3539import Data.Foldable (fold )
3640import Data.Int (fromNumber , toNumber )
3741import Data.Maybe (fromMaybe )
3842import Data.Monoid.Additive (Additive (..), runAdditive )
3943import Data.Traversable (sequence )
4044import Data.Tuple (Tuple (..), fst , snd )
41- import Data.List (List (..))
45+ import Data.Either (Either (..))
46+ import Data.List (List (..), fromList )
4247import Test.QuickCheck.LCG
4348import qualified Math as M
4449
@@ -49,33 +54,30 @@ type Size = Int
4954-- | The state of the random generator monad
5055type GenState = { newSeed :: Seed , size :: Size }
5156
52- -- | The output of the random generator monad
53- type GenOut a = { state :: GenState , value :: a }
54-
5557-- | The random generator monad
5658-- |
5759-- | `Gen` is a state monad which encodes a linear congruential generator.
58- data Gen a = Gen ( GenState -> GenOut a )
60+ type Gen a = State GenState a
5961
6062-- | Create a random generator for a function type.
6163repeatable :: forall a b . (a -> Gen b ) -> Gen (a -> b )
62- repeatable f = Gen $ \s -> { value: \a -> (runGen (f a) s).value, state: s }
64+ repeatable f = state $ \s -> Tuple ( \a -> fst (runGen (f a) s)) s
6365
6466-- | Create a random generator which uses the generator state explicitly.
6567stateful :: forall a . (GenState -> Gen a ) -> Gen a
66- stateful f = Gen ( \s -> runGen (f s) s)
68+ stateful f = state $ \s -> runGen (f s) s
6769
6870-- | Modify a random generator by setting a new random seed.
6971variant :: forall a . Seed -> Gen a -> Gen a
70- variant n g = Gen $ \s -> runGen g s { newSeed = n }
72+ variant n g = state $ \s -> runGen g s { newSeed = n }
7173
7274-- | Create a random generator which depends on the size parameter.
7375sized :: forall a . (Size -> Gen a ) -> Gen a
7476sized f = stateful (\s -> f s.size)
7577
7678-- | Modify a random generator by setting a new size parameter.
7779resize :: forall a . Size -> Gen a -> Gen a
78- resize sz g = Gen $ \s -> runGen g s { size = sz }
80+ resize sz g = state $ \s -> runGen g s { size = sz }
7981
8082-- | Create a random generator which samples a range of `Number`s i
8183-- | with uniform probability.
@@ -127,11 +129,21 @@ arrayOf1 g = sized $ \n ->
127129 xs <- vectorOf (k - one) g
128130 return $ Tuple x xs
129131
132+ replicateMRec :: forall m a . (MonadRec m ) => Int -> m a -> m (List a )
133+ replicateMRec k _ | k <= 0 = return Nil
134+ replicateMRec k gen = tailRecM go (Tuple Nil k)
135+ where
136+ go :: (Tuple (List a ) Int ) -> m (Either (Tuple (List a ) Int ) (List a ))
137+ go (Tuple acc 0 ) = return $ Right acc
138+ go (Tuple acc n) = gen <#> \x -> Left (Tuple (Cons x acc) (n - 1 ))
139+
140+ -- | Create a random generator which generates a list of random values of the specified size.
141+ listOf :: forall a . Int -> Gen a -> Gen (List a )
142+ listOf = replicateMRec
143+
130144-- | Create a random generator which generates a vector of random values of a specified size.
131145vectorOf :: forall a . Int -> Gen a -> Gen (Array a )
132- vectorOf k g
133- | k <= 0 = return []
134- | otherwise = sequence $ const g <$> range one k
146+ vectorOf k g = fromList <$> listOf k g
135147
136148-- | Create a random generator which selects a value from a non-empty collection with
137149-- | uniform probability.
@@ -141,12 +153,12 @@ elements x xs = do
141153 pure if n == zero then x else fromMaybe x (xs !! (n - one))
142154
143155-- | Run a random generator
144- runGen :: forall a . Gen a -> GenState -> GenOut a
145- runGen ( Gen f) = f
156+ runGen :: forall a . Gen a -> GenState -> Tuple a GenState
157+ runGen = runState
146158
147159-- | Run a random generator, keeping only the randomly-generated result
148160evalGen :: forall a . Gen a -> GenState -> a
149- evalGen gen st = (runGen gen st).value
161+ evalGen = evalState
150162
151163-- | Sample a random generator
152164sample :: forall r a . Seed -> Size -> Gen a -> Array a
@@ -164,8 +176,8 @@ randomSample = randomSample' 10
164176
165177-- | A random generator which simply outputs the current seed
166178lcgStep :: Gen Int
167- lcgStep = Gen f where
168- f s = { value: runSeed s.newSeed, state: s { newSeed = lcgNext s.newSeed } }
179+ lcgStep = state f where
180+ f s = Tuple ( runSeed s.newSeed) ( s { newSeed = lcgNext s.newSeed })
169181
170182-- | A random generator which approximates a uniform random variable on `[0, 1]`
171183uniform :: Gen Number
@@ -175,25 +187,8 @@ foreign import float32ToInt32 :: Number -> Int
175187
176188-- | Perturb a random generator by modifying the current seed
177189perturbGen :: forall a . Number -> Gen a -> Gen a
178- perturbGen n (Gen f) = Gen $ \s -> f (s { newSeed = perturb s.newSeed })
190+ perturbGen n gen = do
191+ modify \s -> s { newSeed = perturb s.newSeed }
192+ gen
179193 where
180194 perturb oldSeed = mkSeed (runSeed (lcgNext (mkSeed (float32ToInt32 n))) + runSeed oldSeed)
181-
182- instance functorGen :: Functor Gen where
183- map f (Gen g) = Gen $ \s -> case g s of
184- { value = value, state = state } -> { value: f value, state: state }
185-
186- instance applyGen :: Apply Gen where
187- apply (Gen f) (Gen x) = Gen $ \s ->
188- case f s of
189- { value = f', state = s' } -> case x s' of
190- { value = x', state = s'' } -> { value: f' x', state: s'' }
191-
192- instance applicativeGen :: Applicative Gen where
193- pure a = Gen (\s -> { value: a, state: s })
194-
195- instance bindGen :: Bind Gen where
196- bind (Gen f) g = Gen $ \s -> case f s of
197- { value = value, state = state } -> runGen (g value) state
198-
199- instance monadGen :: Monad Gen
0 commit comments