Skip to content

Commit ad07c79

Browse files
paf31garyb
authored andcommitted
Use Eff for tailrec, not transformers
1 parent 7790957 commit ad07c79

File tree

1 file changed

+30
-26
lines changed

1 file changed

+30
-26
lines changed

src/Test/QuickCheck.purs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,19 @@ import Prelude
3535

3636
import Control.Monad.Eff (Eff())
3737
import Control.Monad.Eff.Console (CONSOLE(), log)
38-
import Control.Monad.Eff.Exception (EXCEPTION(), throwException, error)
38+
import Control.Monad.Eff.Exception (EXCEPTION, throwException, error)
3939
import Control.Monad.Eff.Random (RANDOM())
40-
import Control.Monad.Except.Trans (ExceptT, runExceptT, throwError)
41-
import Control.Monad.State (State)
42-
import Control.Monad.Trans (lift)
43-
import Control.Monad.Writer.Trans (WriterT, runWriterT, tell)
4440
import Control.Monad.Rec.Class (tailRecM)
45-
4641
import Data.Either (Either(..))
47-
import Data.List (List(..))
48-
import Data.Monoid.Additive (Additive(..))
42+
import Data.Foldable (for_)
43+
import Data.List (List)
44+
import Data.Maybe (Maybe(..))
45+
import Data.Maybe.First (First(..))
46+
import Data.Monoid (mempty)
4947
import Data.Tuple (Tuple(..))
5048
import Data.Unfoldable (replicateA)
51-
5249
import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary)
53-
import Test.QuickCheck.Gen (Gen, GenState, evalGen)
50+
import Test.QuickCheck.Gen (Gen, evalGen, runGen)
5451
import Test.QuickCheck.LCG (Seed, randomSeed)
5552

5653
-- | A type synonym which represents the effects used by the `quickCheck` function.
@@ -68,23 +65,30 @@ quickCheck prop = quickCheck' 100 prop
6865
quickCheck' :: forall eff prop. Testable prop => Int -> prop -> QC eff Unit
6966
quickCheck' n prop = do
7067
seed <- randomSeed
71-
case evalGen (runExceptT (runWriterT (tailRecM loop 0))) { newSeed: seed, size: 10 } of
72-
Left err -> throwException $ error $ "Test " <> show (err.index + 1) <> " failed: \n" <> err.msg
73-
Right (Tuple _ (Additive successes)) -> do
74-
log $ show successes <> "/" <> show n <> " test(s) passed."
68+
{ successes, firstFailure } <- tailRecM loop { seed, index: 0, successes: 0, firstFailure: mempty }
69+
log $ show successes <> "/" <> show n <> " test(s) passed."
70+
for_ firstFailure \{ index, message } ->
71+
throwException $ error $ "Test " <> show (index + 1) <> " failed: \n" <> message
7572
where
76-
loop :: Int
77-
-> WriterT (Additive Int)
78-
(ExceptT { index :: Int, msg :: String }
79-
(State GenState)) (Either Int Unit)
80-
loop index | index == n = pure (Right unit)
81-
loop index = do
82-
result <- lift (lift (test prop))
83-
case result of
84-
Success -> do
85-
tell (Additive 1)
86-
pure (Left (index + 1))
87-
Failed msg -> throwError { index, msg }
73+
loop :: { seed :: Seed, index :: Int, successes :: Int, firstFailure :: First { index :: Int, message :: String } }
74+
-> QC eff (Either { seed :: Seed, index :: Int, successes :: Int, firstFailure :: First { index :: Int, message :: String } }
75+
{ successes :: Int, firstFailure :: First { index :: Int, message :: String } })
76+
loop { seed, index, successes, firstFailure }
77+
| index == n = pure (Right { successes, firstFailure })
78+
| otherwise = do
79+
case runGen (test prop) { newSeed: seed, size: 10 } of
80+
Tuple Success s ->
81+
pure (Left { seed: s.newSeed
82+
, index: index + 1
83+
, successes: successes + 1
84+
, firstFailure
85+
})
86+
Tuple (Failed message) s ->
87+
pure (Left { seed: s.newSeed
88+
, index: index + 1
89+
, successes
90+
, firstFailure: firstFailure <> First (Just { index, message })
91+
})
8892

8993
-- | Test a property, returning all test results as an array.
9094
-- |

0 commit comments

Comments
 (0)