22-- | module, as well as helper functions for constructing random generators.
33module Test.QuickCheck.Gen
44 ( Gen
5+ , unGen
56 , GenState
67 , Size
78 , repeatable
@@ -29,19 +30,22 @@ module Test.QuickCheck.Gen
2930
3031import Prelude
3132
33+ import Control.Alt (class Alt )
3234import Control.Monad.Eff (Eff )
3335import Control.Monad.Eff.Random (RANDOM )
34- import Control.Monad.Rec.Class (class MonadRec , tailRecM )
36+ import Control.Monad.Rec.Class (class MonadRec , Step (..), tailRecM )
3537import Control.Monad.State (State , runState , evalState )
3638import Control.Monad.State.Class (state , modify )
39+ import Control.Monad.State.Trans (StateT )
3740
3841import Data.Array ((!!), length )
39- import Data.Either (Either (..))
4042import Data.Foldable (fold )
43+ import Data.Identity (Identity )
4144import Data.Int (toNumber )
4245import Data.List (List (..), toUnfoldable )
4346import Data.Maybe (fromMaybe )
44- import Data.Monoid.Additive (Additive (..), runAdditive )
47+ import Data.Monoid.Additive (Additive (..))
48+ import Data.Newtype (unwrap )
4549import Data.Tuple (Tuple (..), fst , snd )
4650
4751import Math as M
@@ -58,27 +62,39 @@ type GenState = { newSeed :: Seed, size :: Size }
5862-- | The random generator monad
5963-- |
6064-- | `Gen` is a state monad which encodes a linear congruential generator.
61- type Gen a = State GenState a
65+ newtype Gen a = Gen (StateT GenState Identity a )
66+
67+ derive newtype instance functorGen :: Functor Gen
68+ derive newtype instance applyGen :: Apply Gen
69+ derive newtype instance applicativeGen :: Applicative Gen
70+ derive newtype instance bindGen :: Bind Gen
71+ derive newtype instance monadGen :: Monad Gen
72+ derive newtype instance altGen :: Alt Gen
73+ derive newtype instance monadRecGen :: MonadRec Gen
74+
75+ -- | Exposes the underlying State implementation.
76+ unGen :: forall a . Gen a -> State GenState a
77+ unGen (Gen st) = st
6278
6379-- | Create a random generator for a function type.
6480repeatable :: forall a b . (a -> Gen b ) -> Gen (a -> b )
65- repeatable f = state $ \s -> Tuple (\a -> fst (runGen (f a) s)) (s { newSeed = lcgNext s.newSeed })
81+ repeatable f = Gen $ state \s -> Tuple (\a -> fst (runGen (f a) s)) (s { newSeed = lcgNext s.newSeed })
6682
6783-- | Create a random generator which uses the generator state explicitly.
6884stateful :: forall a . (GenState -> Gen a ) -> Gen a
69- stateful f = state $ \s -> runGen (f s) s
85+ stateful f = Gen $ state \s -> runGen (f s) s
7086
7187-- | Modify a random generator by setting a new random seed.
7288variant :: forall a . Seed -> Gen a -> Gen a
73- variant n g = state $ \s -> runGen g s { newSeed = n }
89+ variant n g = Gen $ state \s -> runGen g s { newSeed = n }
7490
7591-- | Create a random generator which depends on the size parameter.
7692sized :: forall a . (Size -> Gen a ) -> Gen a
7793sized f = stateful (\s -> f s.size)
7894
7995-- | Modify a random generator by setting a new size parameter.
8096resize :: forall a . Size -> Gen a -> Gen a
81- resize sz g = state $ \s -> runGen g s { size = sz }
97+ resize sz g = Gen $ state \s -> runGen g s { size = sz }
8298
8399-- | Create a random generator which samples a range of `Number`s i
84100-- | with uniform probability.
@@ -109,7 +125,7 @@ oneOf x xs = do
109125frequency :: forall a . Tuple Number (Gen a ) -> List (Tuple Number (Gen a )) -> Gen a
110126frequency x xs = let
111127 xxs = Cons x xs
112- total = runAdditive $ fold (map (Additive <<< fst) xxs :: List (Additive Number ))
128+ total = unwrap $ fold (map (Additive <<< fst) xxs :: List (Additive Number ))
113129 pick n d Nil = d
114130 pick n d (Cons (Tuple k x) xs) = if n <= k then x else pick (n - k) d xs
115131 in do
@@ -134,9 +150,9 @@ replicateMRec :: forall m a. MonadRec m => Int -> m a -> m (List a)
134150replicateMRec k _ | k <= 0 = pure Nil
135151replicateMRec k gen = tailRecM go (Tuple Nil k)
136152 where
137- go :: (Tuple (List a ) Int ) -> m (Either (Tuple (List a ) Int ) (List a ))
138- go (Tuple acc 0 ) = pure $ Right acc
139- go (Tuple acc n) = gen <#> \x -> Left (Tuple (Cons x acc) (n - 1 ))
153+ go :: (Tuple (List a ) Int ) -> m (Step (Tuple (List a ) Int ) (List a ))
154+ go (Tuple acc 0 ) = pure $ Done acc
155+ go (Tuple acc n) = gen <#> \x -> Loop (Tuple (Cons x acc) (n - 1 ))
140156
141157-- | Create a random generator which generates a list of random values of the specified size.
142158listOf :: forall a . Int -> Gen a -> Gen (List a )
@@ -155,11 +171,11 @@ elements x xs = do
155171
156172-- | Run a random generator
157173runGen :: forall a . Gen a -> GenState -> Tuple a GenState
158- runGen = runState
174+ runGen = runState <<< unGen
159175
160176-- | Run a random generator, keeping only the randomly-generated result
161177evalGen :: forall a . Gen a -> GenState -> a
162- evalGen = evalState
178+ evalGen = evalState <<< unGen
163179
164180-- | Sample a random generator
165181sample :: forall a . Seed -> Size -> Gen a -> Array a
@@ -177,7 +193,7 @@ randomSample = randomSample' 10
177193
178194-- | A random generator which simply outputs the current seed
179195lcgStep :: Gen Int
180- lcgStep = state f where
196+ lcgStep = Gen $ state f where
181197 f s = Tuple (runSeed s.newSeed) (s { newSeed = lcgNext s.newSeed })
182198
183199-- | A random generator which approximates a uniform random variable on `[0, 1]`
@@ -188,6 +204,6 @@ foreign import float32ToInt32 :: Number -> Int
188204
189205-- | Perturb a random generator by modifying the current seed
190206perturbGen :: forall a . Number -> Gen a -> Gen a
191- perturbGen n gen = do
207+ perturbGen n gen = Gen do
192208 modify \s -> s { newSeed = lcgPerturb (toNumber (float32ToInt32 n)) s.newSeed }
193- gen
209+ unGen gen
0 commit comments