3
3
module Test.QuickCheck.Gen
4
4
( Gen ()
5
5
, GenState ()
6
- , GenOut ()
7
6
, Size ()
8
7
, repeatable
9
8
, stateful
@@ -16,6 +15,7 @@ module Test.QuickCheck.Gen
16
15
, frequency
17
16
, arrayOf
18
17
, arrayOf1
18
+ , listOf
19
19
, vectorOf
20
20
, elements
21
21
, runGen
@@ -31,14 +31,19 @@ import Prelude
31
31
32
32
import Control.Monad.Eff (Eff ())
33
33
import 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 )
34
37
import Data.Array ((!!), length , range )
38
+ import Data.Tuple (Tuple (..))
35
39
import Data.Foldable (fold )
36
40
import Data.Int (fromNumber , toNumber )
37
41
import Data.Maybe (fromMaybe )
38
42
import Data.Monoid.Additive (Additive (..), runAdditive )
39
43
import Data.Traversable (sequence )
40
44
import Data.Tuple (Tuple (..), fst , snd )
41
- import Data.List (List (..))
45
+ import Data.Either (Either (..))
46
+ import Data.List (List (..), fromList )
42
47
import Test.QuickCheck.LCG
43
48
import qualified Math as M
44
49
@@ -49,33 +54,30 @@ type Size = Int
49
54
-- | The state of the random generator monad
50
55
type GenState = { newSeed :: Seed , size :: Size }
51
56
52
- -- | The output of the random generator monad
53
- type GenOut a = { state :: GenState , value :: a }
54
-
55
57
-- | The random generator monad
56
58
-- |
57
59
-- | `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
59
61
60
62
-- | Create a random generator for a function type.
61
63
repeatable :: 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
63
65
64
66
-- | Create a random generator which uses the generator state explicitly.
65
67
stateful :: 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
67
69
68
70
-- | Modify a random generator by setting a new random seed.
69
71
variant :: 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 }
71
73
72
74
-- | Create a random generator which depends on the size parameter.
73
75
sized :: forall a . (Size -> Gen a ) -> Gen a
74
76
sized f = stateful (\s -> f s.size)
75
77
76
78
-- | Modify a random generator by setting a new size parameter.
77
79
resize :: 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 }
79
81
80
82
-- | Create a random generator which samples a range of `Number`s i
81
83
-- | with uniform probability.
@@ -127,11 +129,21 @@ arrayOf1 g = sized $ \n ->
127
129
xs <- vectorOf (k - one) g
128
130
return $ Tuple x xs
129
131
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
+
130
144
-- | Create a random generator which generates a vector of random values of a specified size.
131
145
vectorOf :: 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
135
147
136
148
-- | Create a random generator which selects a value from a non-empty collection with
137
149
-- | uniform probability.
@@ -141,12 +153,12 @@ elements x xs = do
141
153
pure if n == zero then x else fromMaybe x (xs !! (n - one))
142
154
143
155
-- | 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
146
158
147
159
-- | Run a random generator, keeping only the randomly-generated result
148
160
evalGen :: forall a . Gen a -> GenState -> a
149
- evalGen gen st = (runGen gen st).value
161
+ evalGen = evalState
150
162
151
163
-- | Sample a random generator
152
164
sample :: forall r a . Seed -> Size -> Gen a -> Array a
@@ -164,8 +176,8 @@ randomSample = randomSample' 10
164
176
165
177
-- | A random generator which simply outputs the current seed
166
178
lcgStep :: 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 })
169
181
170
182
-- | A random generator which approximates a uniform random variable on `[0, 1]`
171
183
uniform :: Gen Number
@@ -175,25 +187,8 @@ foreign import float32ToInt32 :: Number -> Int
175
187
176
188
-- | Perturb a random generator by modifying the current seed
177
189
perturbGen :: 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
179
193
where
180
194
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