From 3bdf6f68eb9eb2969c935c23a76cfa1e81e357a0 Mon Sep 17 00:00:00 2001 From: Phil Freeman Date: Tue, 15 Dec 2015 17:27:11 -0800 Subject: [PATCH] Fix 'repeatable' --- docs/Test/QuickCheck.md | 14 +++--- docs/Test/QuickCheck/Arbitrary.md | 54 ++++++++++++--------- docs/Test/QuickCheck/Data/AlphaNumString.md | 4 +- docs/Test/QuickCheck/Data/ApproxNumber.md | 18 +++---- docs/Test/QuickCheck/Gen.md | 2 +- docs/Test/QuickCheck/LCG.md | 12 ++++- src/Test/QuickCheck/Gen.purs | 10 ++-- src/Test/QuickCheck/LCG.purs | 11 +++-- 8 files changed, 72 insertions(+), 53 deletions(-) diff --git a/docs/Test/QuickCheck.md b/docs/Test/QuickCheck.md index 00905a6..513642f 100644 --- a/docs/Test/QuickCheck.md +++ b/docs/Test/QuickCheck.md @@ -73,9 +73,9 @@ Testable properties can be passed to the `quickCheck` function. ##### Instances ``` purescript -instance testableResult :: Testable Result -instance testableBoolean :: Testable Boolean -instance testableFunction :: (Arbitrary t, Testable prop) => Testable (t -> prop) +Testable Result +Testable Boolean +(Arbitrary t, Testable prop) => Testable (t -> prop) ``` #### `Result` @@ -90,8 +90,8 @@ The result of a test: success or failure (with an error message). ##### Instances ``` purescript -instance testableResult :: Testable Result -instance showResult :: Show Result +Testable Result +Show Result ``` #### `()` @@ -113,7 +113,7 @@ test x = myProperty x ("myProperty did not hold for " <> show x) #### `(===)` ``` purescript -(===) :: forall a b. (Eq a, Show a) => a -> a -> Result +(===) :: forall a. (Eq a, Show a) => a -> a -> Result ``` _left-associative / precedence -1_ @@ -123,7 +123,7 @@ Self-documenting equality assertion #### `(/==)` ``` purescript -(/==) :: forall a b. (Eq a, Show a) => a -> a -> Result +(/==) :: forall a. (Eq a, Show a) => a -> a -> Result ``` _left-associative / precedence -1_ diff --git a/docs/Test/QuickCheck/Arbitrary.md b/docs/Test/QuickCheck/Arbitrary.md index 33e4972..bfb214a 100644 --- a/docs/Test/QuickCheck/Arbitrary.md +++ b/docs/Test/QuickCheck/Arbitrary.md @@ -16,18 +16,21 @@ module can be used to construct random generators. ##### Instances ``` purescript -instance arbBoolean :: Arbitrary Boolean -instance arbNumber :: Arbitrary Number -instance arbInt :: Arbitrary Int -instance arbString :: Arbitrary String -instance arbChar :: Arbitrary Char -instance arbUnit :: Arbitrary Unit -instance arbOrdering :: Arbitrary Ordering -instance arbArray :: (Arbitrary a) => Arbitrary (Array a) -instance arbFunction :: (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b) -instance arbTuple :: (Arbitrary a, Arbitrary b) => Arbitrary (Tuple a b) -instance arbMaybe :: (Arbitrary a) => Arbitrary (Maybe a) -instance arbEither :: (Arbitrary a, Arbitrary b) => Arbitrary (Either a b) +Arbitrary Boolean +Arbitrary Number +Arbitrary Int +Arbitrary String +Arbitrary Char +Arbitrary Unit +Arbitrary Ordering +(Arbitrary a) => Arbitrary (Array a) +(Coarbitrary a, Arbitrary b) => Arbitrary (a -> b) +(Arbitrary a, Arbitrary b) => Arbitrary (Tuple a b) +(Arbitrary a) => Arbitrary (Maybe a) +(Arbitrary a, Arbitrary b) => Arbitrary (Either a b) +(Arbitrary a) => Arbitrary (List a) +(Arbitrary a) => Arbitrary (Identity a) +(Arbitrary a) => Arbitrary (Lazy a) ``` #### `Coarbitrary` @@ -48,18 +51,21 @@ is the role of the `coarbitrary` function. ##### Instances ``` purescript -instance coarbBoolean :: Coarbitrary Boolean -instance coarbNumber :: Coarbitrary Number -instance coarbInt :: Coarbitrary Int -instance coarbString :: Coarbitrary String -instance coarbChar :: Coarbitrary Char -instance coarbUnit :: Coarbitrary Unit -instance coarbOrdering :: Coarbitrary Ordering -instance coarbArray :: (Coarbitrary a) => Coarbitrary (Array a) -instance coarbFunction :: (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b) -instance coarbTuple :: (Coarbitrary a, Coarbitrary b) => Coarbitrary (Tuple a b) -instance coarbMaybe :: (Coarbitrary a) => Coarbitrary (Maybe a) -instance coarbEither :: (Coarbitrary a, Coarbitrary b) => Coarbitrary (Either a b) +Coarbitrary Boolean +Coarbitrary Number +Coarbitrary Int +Coarbitrary String +Coarbitrary Char +Coarbitrary Unit +Coarbitrary Ordering +(Coarbitrary a) => Coarbitrary (Array a) +(Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b) +(Coarbitrary a, Coarbitrary b) => Coarbitrary (Tuple a b) +(Coarbitrary a) => Coarbitrary (Maybe a) +(Coarbitrary a, Coarbitrary b) => Coarbitrary (Either a b) +(Coarbitrary a) => Coarbitrary (List a) +(Coarbitrary a) => Coarbitrary (Identity a) +(Coarbitrary a) => Coarbitrary (Lazy a) ``` diff --git a/docs/Test/QuickCheck/Data/AlphaNumString.md b/docs/Test/QuickCheck/Data/AlphaNumString.md index 15e9388..0fa5804 100644 --- a/docs/Test/QuickCheck/Data/AlphaNumString.md +++ b/docs/Test/QuickCheck/Data/AlphaNumString.md @@ -12,8 +12,8 @@ alphanumeric strings. ##### Instances ``` purescript -instance arbAlphaNumString :: Arbitrary AlphaNumString -instance coarbAlphaNumString :: Coarbitrary AlphaNumString +Arbitrary AlphaNumString +Coarbitrary AlphaNumString ``` #### `runAlphaNumString` diff --git a/docs/Test/QuickCheck/Data/ApproxNumber.md b/docs/Test/QuickCheck/Data/ApproxNumber.md index d26a818..ada77f0 100644 --- a/docs/Test/QuickCheck/Data/ApproxNumber.md +++ b/docs/Test/QuickCheck/Data/ApproxNumber.md @@ -12,15 +12,15 @@ for precision erros when comparing. ##### Instances ``` purescript -instance arbitraryApproxNumber :: Arbitrary ApproxNumber -instance coarbitraryApproxNumber :: Coarbitrary ApproxNumber -instance eqApproxNumber :: Eq ApproxNumber -instance ordApproxNumber :: Ord ApproxNumber -instance semiringApproxNumber :: Semiring ApproxNumber -instance moduloSemiringApproxNumber :: ModuloSemiring ApproxNumber -instance ringApproxNumber :: Ring ApproxNumber -instance divisionRingApproxNumber :: DivisionRing ApproxNumber -instance numApproxNumber :: Num ApproxNumber +Arbitrary ApproxNumber +Coarbitrary ApproxNumber +Eq ApproxNumber +Ord ApproxNumber +Semiring ApproxNumber +ModuloSemiring ApproxNumber +Ring ApproxNumber +DivisionRing ApproxNumber +Num ApproxNumber ``` #### `(=~=)` diff --git a/docs/Test/QuickCheck/Gen.md b/docs/Test/QuickCheck/Gen.md index baa23bf..60e9728 100644 --- a/docs/Test/QuickCheck/Gen.md +++ b/docs/Test/QuickCheck/Gen.md @@ -166,7 +166,7 @@ Run a random generator, keeping only the randomly-generated result #### `sample` ``` purescript -sample :: forall r a. Seed -> Size -> Gen a -> Array a +sample :: forall a. Seed -> Size -> Gen a -> Array a ``` Sample a random generator diff --git a/docs/Test/QuickCheck/LCG.md b/docs/Test/QuickCheck/LCG.md index 13872b0..1fbcb81 100644 --- a/docs/Test/QuickCheck/LCG.md +++ b/docs/Test/QuickCheck/LCG.md @@ -27,6 +27,14 @@ It is equal to 2^31 - 1, a Mersenne prime. It is useful for this value to be prime, because then the requirement of the initial seed being coprime to the modulus is satisfied when the seed is between 1 and lcgN - 1. +#### `lcgPerturb` + +``` purescript +lcgPerturb :: Number -> Seed -> Seed +``` + +Perturb a seed value + #### `lcgNext` ``` purescript @@ -55,8 +63,8 @@ seed for the generator. ##### Instances ``` purescript -instance showSeed :: Show Seed -instance eqSeed :: Eq Seed +Show Seed +Eq Seed ``` #### `mkSeed` diff --git a/src/Test/QuickCheck/Gen.purs b/src/Test/QuickCheck/Gen.purs index bcce98d..32b2563 100644 --- a/src/Test/QuickCheck/Gen.purs +++ b/src/Test/QuickCheck/Gen.purs @@ -34,11 +34,13 @@ import Control.Monad.Eff.Random (RANDOM()) import Control.Monad.State (State(), runState, evalState) import Control.Monad.State.Class (state, modify) import Control.Monad.Rec.Class (MonadRec, tailRecM) +import Math ((%)) import Data.Array ((!!), length) import Data.Tuple (Tuple(..)) import Data.Foldable (fold) -import Data.Int (toNumber) +import Data.Int (toNumber, fromNumber) import Data.Maybe (fromMaybe) +import Data.Maybe.Unsafe as U import Data.Monoid.Additive (Additive(..), runAdditive) import Data.Tuple (Tuple(..), fst, snd) import Data.Either (Either(..)) @@ -60,7 +62,7 @@ type Gen a = State GenState a -- | Create a random generator for a function type. repeatable :: forall a b. (a -> Gen b) -> Gen (a -> b) -repeatable f = state $ \s -> Tuple (\a -> fst (runGen (f a) s)) s +repeatable f = state $ \s -> Tuple (\a -> fst (runGen (f a) s)) (s { newSeed = lcgNext s.newSeed }) -- | Create a random generator which uses the generator state explicitly. stateful :: forall a. (GenState -> Gen a) -> Gen a @@ -187,7 +189,5 @@ foreign import float32ToInt32 :: Number -> Int -- | Perturb a random generator by modifying the current seed perturbGen :: forall a. Number -> Gen a -> Gen a perturbGen n gen = do - modify \s -> s { newSeed = perturb s.newSeed } + modify \s -> s { newSeed = lcgPerturb (toNumber (float32ToInt32 n)) s.newSeed } gen - where - perturb oldSeed = mkSeed (runSeed (lcgNext (mkSeed (float32ToInt32 n))) + runSeed oldSeed) diff --git a/src/Test/QuickCheck/LCG.purs b/src/Test/QuickCheck/LCG.purs index c2cc9ac..038880b 100644 --- a/src/Test/QuickCheck/LCG.purs +++ b/src/Test/QuickCheck/LCG.purs @@ -6,6 +6,7 @@ module Test.QuickCheck.LCG , lcgC , lcgN , lcgNext + , lcgPerturb , randomSeed ) where @@ -32,11 +33,15 @@ lcgC = 0 lcgN :: Int lcgN = 2147483647 +-- | Perturb a seed value +lcgPerturb :: Number -> Seed -> Seed +lcgPerturb d = Seed <<< go <<< runSeed + where + go n = U.fromJust $ fromNumber $ (toNumber lcgM * toNumber n + d) % toNumber lcgN + -- | Step the linear congruential generator lcgNext :: Seed -> Seed -lcgNext = Seed <<< go <<< runSeed - where - go n = U.fromJust $ fromNumber $ (toNumber lcgM * toNumber n + toNumber lcgC) % toNumber lcgN +lcgNext = lcgPerturb (toNumber lcgC) -- | Create a random seed randomSeed :: forall e. Eff (random :: RANDOM | e) Seed