packages feed

smallcheck 0.6.2 → 1.0

raw patch · 33 files changed

+970/−1820 lines, 33 filesdep +logictdep +mtldep +prettydep −dlistdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: logict, mtl, pretty

Dependencies removed: dlist

Dependency ranges changed: base

API changes (from Hackage documentation)

- Test.SmallCheck: depthCheck :: Testable a => Depth -> a -> IO ()
- Test.SmallCheck: exists1 :: (Show a, Serial a, Testable b) => (a -> b) -> Property
- Test.SmallCheck: exists1DeeperBy :: (Show a, Serial a, Testable b) => (Depth -> Depth) -> (a -> b) -> Property
- Test.SmallCheck: existsDeeperBy :: (Show a, Serial a, Testable b) => (Depth -> Depth) -> (a -> b) -> Property
- Test.SmallCheck: property :: Testable a => a -> Property
- Test.SmallCheck: smallCheckI :: Testable a => a -> IO ()
- Test.SmallCheck.Drivers: depthCheck :: Testable a => Depth -> a -> IO ()
- Test.SmallCheck.Drivers: smallCheckI :: Testable a => a -> IO ()
- Test.SmallCheck.Drivers: smallCheckPure :: Testable a => Depth -> a -> Either [String] (Integer, Integer)
- Test.SmallCheck.Property: (==>) :: Testable a => Bool -> a -> Property
- Test.SmallCheck.Property: Fail :: TestResult
- Test.SmallCheck.Property: Inappropriate :: TestResult
- Test.SmallCheck.Property: Pass :: TestResult
- Test.SmallCheck.Property: TestCase :: TestResult -> [String] -> TestCase
- Test.SmallCheck.Property: arguments :: TestCase -> [String]
- Test.SmallCheck.Property: class Testable a
- Test.SmallCheck.Property: data Property
- Test.SmallCheck.Property: data TestCase
- Test.SmallCheck.Property: data TestResult
- Test.SmallCheck.Property: exists :: (Show a, Serial a, Testable b) => (a -> b) -> Property
- Test.SmallCheck.Property: exists1 :: (Show a, Serial a, Testable b) => (a -> b) -> Property
- Test.SmallCheck.Property: exists1DeeperBy :: (Show a, Serial a, Testable b) => (Depth -> Depth) -> (a -> b) -> Property
- Test.SmallCheck.Property: existsDeeperBy :: (Show a, Serial a, Testable b) => (Depth -> Depth) -> (a -> b) -> Property
- Test.SmallCheck.Property: forAll :: (Show a, Testable b) => Series a -> (a -> b) -> Property
- Test.SmallCheck.Property: forAllElem :: (Show a, Testable b) => [a] -> (a -> b) -> Property
- Test.SmallCheck.Property: instance (Serial a, Show a, Testable b) => Testable (a -> b)
- Test.SmallCheck.Property: instance Testable Bool
- Test.SmallCheck.Property: instance Testable Property
- Test.SmallCheck.Property: instance Typeable Property
- Test.SmallCheck.Property: mkProperty :: (Depth -> [TestCase]) -> Property
- Test.SmallCheck.Property: property :: Testable a => a -> Property
- Test.SmallCheck.Property: result :: TestCase -> TestResult
- Test.SmallCheck.Property: resultIsOk :: TestResult -> Bool
- Test.SmallCheck.Property: test :: Testable a => a -> Depth -> [TestCase]
- Test.SmallCheck.Property: thereExists :: (Show a, Testable b) => Series a -> (a -> b) -> Property
- Test.SmallCheck.Property: thereExists1 :: (Show a, Testable b) => Series a -> (a -> b) -> Property
- Test.SmallCheck.Property: thereExists1Elem :: (Show a, Testable b) => [a] -> (a -> b) -> Property
- Test.SmallCheck.Property: thereExistsElem :: (Show a, Testable b) => [a] -> (a -> b) -> Property
- Test.SmallCheck.Property: type Depth = Int
- Test.SmallCheck.Series: N :: a -> N a
- Test.SmallCheck.Series: depth :: Depth -> Depth -> Depth
- Test.SmallCheck.Series: instance (GSerial a, GSerial b) => GSerial (a :*: b)
- Test.SmallCheck.Series: instance (GSerialSum a, GSerialSum b) => GSerial (a :+: b)
- Test.SmallCheck.Series: instance (GSerialSum a, GSerialSum b) => GSerialSum (a :+: b)
- Test.SmallCheck.Series: instance (Integral a, Serial a) => Serial (N a)
- Test.SmallCheck.Series: instance (Serial a, Serial b) => Serial (Either a b)
- Test.SmallCheck.Series: instance (Serial a, Serial b) => Serial (a -> b)
- Test.SmallCheck.Series: instance (Serial a, Serial b) => Serial (a, b)
- Test.SmallCheck.Series: instance (Serial a, Serial b, Serial c) => Serial (a, b, c)
- Test.SmallCheck.Series: instance (Serial a, Serial b, Serial c, Serial d) => Serial (a, b, c, d)
- Test.SmallCheck.Series: instance (Serial a, Show a, Show b) => Show (a -> b)
- Test.SmallCheck.Series: instance GSerial U1
- Test.SmallCheck.Series: instance GSerial f => GSerial (M1 i c f)
- Test.SmallCheck.Series: instance GSerial f => GSerialSum (C1 c f)
- Test.SmallCheck.Series: instance Serial ()
- Test.SmallCheck.Series: instance Serial Bool
- Test.SmallCheck.Series: instance Serial Char
- Test.SmallCheck.Series: instance Serial Double
- Test.SmallCheck.Series: instance Serial Float
- Test.SmallCheck.Series: instance Serial Int
- Test.SmallCheck.Series: instance Serial Integer
- Test.SmallCheck.Series: instance Serial a => Serial (Maybe a)
- Test.SmallCheck.Series: instance Serial a => Serial [a]
- Test.SmallCheck.Series: instance Serial c => GSerial (K1 i c)
- Test.SmallCheck.Series: instance Show a => Show (N a)
- Test.SmallCheck.Series: newtype N a
- Test.SmallCheck.Series: type Nat = N Int
- Test.SmallCheck.Series: type Natural = N Integer
- Test.SmallCheck.Series: type Series a = Depth -> [a]
+ Test.SmallCheck: changeDepth :: Testable m a => (Depth -> Depth) -> a -> Property m
+ Test.SmallCheck: changeDepth1 :: (Show a, Serial m a, Testable m b) => (Depth -> Depth) -> (a -> b) -> Property m
+ Test.SmallCheck: existsUnique :: Testable m a => a -> Property m
+ Test.SmallCheck: forAll :: Testable m a => a -> Property m
+ Test.SmallCheck: monadic :: Testable m a => m a -> Property m
+ Test.SmallCheck: over :: (Monad m, Show a, Testable m b) => Series m a -> (a -> b) -> Property m
+ Test.SmallCheck.Drivers: AtLeastTwo :: [Argument] -> PropertySuccess -> [Argument] -> PropertySuccess -> PropertyFailure
+ Test.SmallCheck.Drivers: BadTest :: TestQuality
+ Test.SmallCheck.Drivers: CounterExample :: [Argument] -> PropertyFailure -> PropertyFailure
+ Test.SmallCheck.Drivers: Exist :: [Argument] -> PropertySuccess -> PropertySuccess
+ Test.SmallCheck.Drivers: ExistUnique :: [Argument] -> PropertySuccess -> PropertySuccess
+ Test.SmallCheck.Drivers: GoodTest :: TestQuality
+ Test.SmallCheck.Drivers: NotExist :: PropertyFailure
+ Test.SmallCheck.Drivers: PropertyFalse :: PropertyFailure
+ Test.SmallCheck.Drivers: PropertyTrue :: PropertySuccess
+ Test.SmallCheck.Drivers: Vacuously :: PropertyFailure -> PropertySuccess
+ Test.SmallCheck.Drivers: data PropertyFailure
+ Test.SmallCheck.Drivers: data PropertySuccess
+ Test.SmallCheck.Drivers: data TestQuality
+ Test.SmallCheck.Drivers: ppFailure :: PropertyFailure -> String
+ Test.SmallCheck.Drivers: smallCheckM :: Testable m a => Depth -> a -> m (Maybe PropertyFailure)
+ Test.SmallCheck.Drivers: smallCheckWithHook :: Testable m a => Depth -> (TestQuality -> m ()) -> a -> m (Maybe PropertyFailure)
+ Test.SmallCheck.Drivers: test :: Testable m a => a -> Property m
+ Test.SmallCheck.Drivers: type Argument = String
+ Test.SmallCheck.Series: (<~>) :: Monad m => Series m (a -> b) -> Series m a -> Series m b
+ Test.SmallCheck.Series: (>>-) :: MonadLogic m => forall a b. m a -> (a -> m b) -> m b
+ Test.SmallCheck.Series: NonNegative :: a -> NonNegative a
+ Test.SmallCheck.Series: Positive :: a -> Positive a
+ Test.SmallCheck.Series: class Monad m => CoSerial m a where coseries rs = (. from) <$> gCoseries rs
+ Test.SmallCheck.Series: data Series m a
+ Test.SmallCheck.Series: decDepth :: Series m a -> Series m a
+ Test.SmallCheck.Series: generate :: (Depth -> [a]) -> Series m a
+ Test.SmallCheck.Series: getDepth :: Series m Depth
+ Test.SmallCheck.Series: getNonNegative :: NonNegative a -> a
+ Test.SmallCheck.Series: getPositive :: Positive a -> a
+ Test.SmallCheck.Series: instance (CoSerial m a, Serial m b, Monad m) => Serial m (a -> b)
+ Test.SmallCheck.Series: instance (Integral a, Serial m a) => CoSerial m (N a)
+ Test.SmallCheck.Series: instance (Integral a, Serial m a) => Serial m (N a)
+ Test.SmallCheck.Series: instance (Monad m, CoSerial m a) => CoSerial m (Maybe a)
+ Test.SmallCheck.Series: instance (Monad m, CoSerial m a, CoSerial m b) => CoSerial m (Either a b)
+ Test.SmallCheck.Series: instance (Monad m, CoSerial m a, CoSerial m b) => CoSerial m (a, b)
+ Test.SmallCheck.Series: instance (Monad m, CoSerial m a, CoSerial m b, CoSerial m c) => CoSerial m (a, b, c)
+ Test.SmallCheck.Series: instance (Monad m, CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d) => CoSerial m (a, b, c, d)
+ Test.SmallCheck.Series: instance (Monad m, GCoSerial m a, GCoSerial m b) => GCoSerial m (a :*: b)
+ Test.SmallCheck.Series: instance (Monad m, GCoSerial m a, GCoSerial m b) => GCoSerial m (a :+: b)
+ Test.SmallCheck.Series: instance (Monad m, GSerial m a, GSerial m b) => GSerial m (a :*: b)
+ Test.SmallCheck.Series: instance (Monad m, GSerial m a, GSerial m b) => GSerial m (a :+: b)
+ Test.SmallCheck.Series: instance (Monad m, Serial m a) => Serial m (Maybe a)
+ Test.SmallCheck.Series: instance (Monad m, Serial m a, Serial m b) => Serial m (Either a b)
+ Test.SmallCheck.Series: instance (Monad m, Serial m a, Serial m b) => Serial m (a, b)
+ Test.SmallCheck.Series: instance (Monad m, Serial m a, Serial m b, Serial m c) => Serial m (a, b, c)
+ Test.SmallCheck.Series: instance (Monad m, Serial m a, Serial m b, Serial m c, Serial m d) => Serial m (a, b, c, d)
+ Test.SmallCheck.Series: instance (Num a, Ord a, Serial m a) => Serial m (NonNegative a)
+ Test.SmallCheck.Series: instance (Num a, Ord a, Serial m a) => Serial m (Positive a)
+ Test.SmallCheck.Series: instance (Serial Identity a, Show a, Show b) => Show (a -> b)
+ Test.SmallCheck.Series: instance (Serial m a, CoSerial m a, Serial m b, CoSerial m b, Monad m) => CoSerial m (a -> b)
+ Test.SmallCheck.Series: instance CoSerial m a => CoSerial m [a]
+ Test.SmallCheck.Series: instance CoSerial m c => GCoSerial m (K1 i c)
+ Test.SmallCheck.Series: instance Enum a => Enum (N a)
+ Test.SmallCheck.Series: instance Enum a => Enum (NonNegative a)
+ Test.SmallCheck.Series: instance Enum a => Enum (Positive a)
+ Test.SmallCheck.Series: instance Eq a => Eq (NonNegative a)
+ Test.SmallCheck.Series: instance Eq a => Eq (Positive a)
+ Test.SmallCheck.Series: instance GCoSerial m U1
+ Test.SmallCheck.Series: instance GCoSerial m f => GCoSerial m (M1 i c f)
+ Test.SmallCheck.Series: instance GSerial m U1
+ Test.SmallCheck.Series: instance GSerial m f => GSerial m (M1 i c f)
+ Test.SmallCheck.Series: instance Integral a => Integral (N a)
+ Test.SmallCheck.Series: instance Integral a => Integral (NonNegative a)
+ Test.SmallCheck.Series: instance Integral a => Integral (Positive a)
+ Test.SmallCheck.Series: instance Monad m => CoSerial m ()
+ Test.SmallCheck.Series: instance Monad m => CoSerial m Bool
+ Test.SmallCheck.Series: instance Monad m => CoSerial m Char
+ Test.SmallCheck.Series: instance Monad m => CoSerial m Double
+ Test.SmallCheck.Series: instance Monad m => CoSerial m Float
+ Test.SmallCheck.Series: instance Monad m => CoSerial m Int
+ Test.SmallCheck.Series: instance Monad m => CoSerial m Integer
+ Test.SmallCheck.Series: instance Monad m => Serial m ()
+ Test.SmallCheck.Series: instance Monad m => Serial m Bool
+ Test.SmallCheck.Series: instance Monad m => Serial m Char
+ Test.SmallCheck.Series: instance Monad m => Serial m Double
+ Test.SmallCheck.Series: instance Monad m => Serial m Float
+ Test.SmallCheck.Series: instance Monad m => Serial m Int
+ Test.SmallCheck.Series: instance Monad m => Serial m Integer
+ Test.SmallCheck.Series: instance Num a => Num (N a)
+ Test.SmallCheck.Series: instance Num a => Num (NonNegative a)
+ Test.SmallCheck.Series: instance Num a => Num (Positive a)
+ Test.SmallCheck.Series: instance Ord a => Ord (NonNegative a)
+ Test.SmallCheck.Series: instance Ord a => Ord (Positive a)
+ Test.SmallCheck.Series: instance Real a => Real (N a)
+ Test.SmallCheck.Series: instance Real a => Real (NonNegative a)
+ Test.SmallCheck.Series: instance Real a => Real (Positive a)
+ Test.SmallCheck.Series: instance Serial m a => Serial m [a]
+ Test.SmallCheck.Series: instance Serial m c => GSerial m (K1 i c)
+ Test.SmallCheck.Series: instance Show a => Show (NonNegative a)
+ Test.SmallCheck.Series: instance Show a => Show (Positive a)
+ Test.SmallCheck.Series: list :: Depth -> Series Identity a -> [a]
+ Test.SmallCheck.Series: localDepth :: (Depth -> Depth) -> Series m a -> Series m a
+ Test.SmallCheck.Series: newtype NonNegative a
+ Test.SmallCheck.Series: newtype Positive a
+ Test.SmallCheck.Series: newtypeAlts :: (Monad m, CoSerial m a) => Series m b -> Series m (a -> b)
+ Test.SmallCheck.Series: newtypeCons :: Serial m a => (a -> b) -> Series m b
- Test.SmallCheck: (==>) :: Testable a => Bool -> a -> Property
+ Test.SmallCheck: (==>) :: (Testable m c, Testable m a) => c -> a -> Property m
- Test.SmallCheck: class Testable a
+ Test.SmallCheck: class Monad m => Testable m a
- Test.SmallCheck: data Property
+ Test.SmallCheck: data Property m
- Test.SmallCheck: exists :: (Show a, Serial a, Testable b) => (a -> b) -> Property
+ Test.SmallCheck: exists :: Testable m a => a -> Property m
- Test.SmallCheck: smallCheck :: Testable a => Depth -> a -> IO ()
+ Test.SmallCheck: smallCheck :: Testable IO a => Depth -> a -> IO ()
- Test.SmallCheck.Drivers: smallCheck :: Testable a => Depth -> a -> IO ()
+ Test.SmallCheck.Drivers: smallCheck :: Testable IO a => Depth -> a -> IO ()
- Test.SmallCheck.Series: (><) :: Series a -> Series b -> Series (a, b)
+ Test.SmallCheck.Series: (><) :: Monad m => Series m a -> Series m b -> Series m (a, b)
- Test.SmallCheck.Series: (\/) :: Series a -> Series a -> Series a
+ Test.SmallCheck.Series: (\/) :: Monad m => Series m a -> Series m a -> Series m a
- Test.SmallCheck.Series: alts0 :: Series a -> Series a
+ Test.SmallCheck.Series: alts0 :: Series m a -> Series m a
- Test.SmallCheck.Series: alts1 :: Serial a => Series b -> Series (a -> b)
+ Test.SmallCheck.Series: alts1 :: (Monad m, CoSerial m a) => Series m b -> Series m (a -> b)
- Test.SmallCheck.Series: alts2 :: (Serial a, Serial b) => Series c -> Series (a -> b -> c)
+ Test.SmallCheck.Series: alts2 :: (CoSerial m a, CoSerial m b) => Series m c -> Series m (a -> b -> c)
- Test.SmallCheck.Series: alts3 :: (Serial a, Serial b, Serial c) => Series d -> Series (a -> b -> c -> d)
+ Test.SmallCheck.Series: alts3 :: (CoSerial m a, CoSerial m b, CoSerial m c) => Series m d -> Series m (a -> b -> c -> d)
- Test.SmallCheck.Series: alts4 :: (Serial a, Serial b, Serial c, Serial d) => Series e -> Series (a -> b -> c -> d -> e)
+ Test.SmallCheck.Series: alts4 :: (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d) => Series m e -> Series m (a -> b -> c -> d -> e)
- Test.SmallCheck.Series: class Serial a where series = map to . gSeries coseries rs = map (. from) . gCoseries rs
+ Test.SmallCheck.Series: class Monad m => Serial m a where series = to <$> gSeries
- Test.SmallCheck.Series: cons0 :: a -> Series a
+ Test.SmallCheck.Series: cons0 :: a -> Series m a
- Test.SmallCheck.Series: cons1 :: Serial a => (a -> b) -> Series b
+ Test.SmallCheck.Series: cons1 :: Serial m a => (a -> b) -> Series m b
- Test.SmallCheck.Series: cons2 :: (Serial a, Serial b) => (a -> b -> c) -> Series c
+ Test.SmallCheck.Series: cons2 :: (Serial m a, Serial m b) => (a -> b -> c) -> Series m c
- Test.SmallCheck.Series: cons3 :: (Serial a, Serial b, Serial c) => (a -> b -> c -> d) -> Series d
+ Test.SmallCheck.Series: cons3 :: (Serial m a, Serial m b, Serial m c) => (a -> b -> c -> d) -> Series m d
- Test.SmallCheck.Series: cons4 :: (Serial a, Serial b, Serial c, Serial d) => (a -> b -> c -> d -> e) -> Series e
+ Test.SmallCheck.Series: cons4 :: (Serial m a, Serial m b, Serial m c, Serial m d) => (a -> b -> c -> d -> e) -> Series m e
- Test.SmallCheck.Series: coseries :: Serial a => Series b -> Series (a -> b)
+ Test.SmallCheck.Series: coseries :: CoSerial m a => Series m b -> Series m (a -> b)
- Test.SmallCheck.Series: series :: Serial a => Series a
+ Test.SmallCheck.Series: series :: Serial m a => Series m a

Files

CHANGES.md view
@@ -1,6 +1,15 @@ Changes ======= +Version 1.0+-----------++This is a major incompatible release of SmallCheck. Virtually every function has+changed its name, type, semantics or module. So please carefully read the docs+when upgrading.++For some highlights, see [this blog post](http://ro-che.info/articles/2013-02-19-smallcheck.html).+ Version 0.6.2 ----------- * Derive Typeable Property instance
README.md view
@@ -13,7 +13,6 @@ To get started with SmallCheck:  * Read the [documentation][haddock]-* Look at some [examples][examples] * If you have experience with QuickCheck, [read the comparison of QuickCheck and SmallCheck][comparison] * Install it and give it a try!     `cabal update; cabal install smallcheck`@@ -24,7 +23,6 @@  [haddock]: http://hackage.haskell.org/packages/archive/smallcheck/latest/doc/html/Test-SmallCheck.html [hackage]: http://hackage.haskell.org/package/smallcheck-[examples]: https://github.com/feuerbach/smallcheck/tree/master/examples [paper]: http://www.cs.york.ac.uk/fp/smallcheck/smallcheck.pdf [oldpage]: http://www.cs.york.ac.uk/fp/smallcheck/ [comparison]: https://github.com/feuerbach/smallcheck/wiki/Comparison-with-QuickCheck
Test/SmallCheck.hs view
@@ -7,6 +7,9 @@ -- -- This module exports the main pieces of SmallCheck functionality. --+-- To generate test cases for your own types, refer to+-- "Test.SmallCheck.Series".+-- -- For pointers to other sources of information about SmallCheck, please refer -- to the README at -- <https://github.com/feuerbach/smallcheck/blob/master/README.md>@@ -15,57 +18,80 @@   -- * Constructing tests    -- | The simplest kind of test is a function (possibly of many-  -- arguments) returning 'Bool'.+  -- arguments) returning 'Bool'. The function arguments are interpreted+  -- as being universally, existentially or uniquely quantified, depending+  -- on the quantification context.   ---  -- In addition, you can use the combinators shown below. For more-  -- advanced combinators, see "Test.SmallCheck.Property".--  Testable,-  Property,-  property,+  -- The default quantification context is universal ('forAll').+  --+  -- 'forAll', 'exists' and 'existsUnique' functions set the quantification+  -- context for function arguments. Depending on the quantification+  -- context, the test @\\x y -> p x y@ may be equivalent to:+  --+  -- * ∀ x, y. p x y ('forAll')+  --+  -- * ∃ x, y: p x y ('exists')+  --+  -- * ∃! x, y: p x y ('existsUnique')+  --+  -- The quantification context affects all the variables immediately+  -- following the quantification operator, also extending past 'over',+  -- 'changeDepth' and 'changeDepth1' functions.+  --+  -- However, it doesn't extend past other functions, like 'monadic', and+  -- doesn't affect the operands of '==>'. Such functions start a fresh+  -- default quantification context. -  -- ** Existential quantification+  -- ** Examples -  -- | Suppose we have defined a function+  -- |+  -- * @\\x y -> p x y@ means ∀ x, y. p x y   ---  -- >isPrefix :: Eq a => [a] -> [a] -> Bool+  -- * @'exists' $ \\x y -> p x y@ means ∃ x, y: p x y   ---  -- and wish to specify it by some suitable property. We might define+  -- * @'exists' $ \\x -> 'forAll' $ \\y -> p x y@ means ∃ x: ∀ y. p x y   ---  -- >prop_isPrefix1 :: String -> String -> Bool-  -- >prop_isPrefix1 xs ys = isPrefix xs (xs++ys)+  -- * @'existsUnique' $ \\x y -> p x y@ means ∃! (x, y): p x y   ---  -- where @xs@ and @ys@ are universally quantified. This property is necessary-  -- but not sufficient for a correct @isPrefix@. For example, it is satisfied-  -- by the function that always returns @True@!+  -- * @'existsUnique' $ \\x -> 'over' s $ \\y -> p x y@ means ∃! (x, y): y ∈ s && p x y   ---  -- We can also test the following property, which involves an existentially-  -- quantified variable:+  -- * @'existsUnique' $ \\x -> 'monadic' $ \\y -> p x y@ means ∃! x: ∀ y. [p x y]   ---  -- >prop_isPrefix2 :: String -> String -> Property-  -- >prop_isPrefix2 xs ys = isPrefix xs ys ==> exists $ \xs' -> ys == xs++xs'+  -- * @'existsUnique' $ \\x -> 'existsUnique' $ \\y -> p x y@ means ∃! x: ∃! y: p x y+  --+  -- * @'exists' $ \\x -> (\\y -> p y) '==>' (\\z -> q z)@ means ∃ x: (∀ y. p y) => (∀ z. p z) +  forAll,   exists,-  exists1,-  existsDeeperBy,-  exists1DeeperBy,+  existsUnique,+  over,+  monadic, -  -- ** Conditioning   (==>),+  changeDepth,+  changeDepth1,    -- * Running tests-  -- | The functions below can be used to run SmallCheck tests.+  -- | 'smallCheck' is a simple way to run a test.   ---  -- As an alternative, consider using @test-framework@ package.+  -- As an alternative, consider using the @test-framework@ package:+  -- <http://hackage.haskell.org/package/test-framework>   --   -- It allows to organize SmallCheck properties into a test suite (possibly   -- together with HUnit or QuickCheck tests), apply timeouts, get nice   -- statistics etc.   --   -- To use SmallCheck properties with test-framework, install-  -- @test-framework-smallcheck@ package.-  smallCheck, depthCheck, smallCheckI,-  Depth+  -- the @test-framework-smallcheck@ package: <http://hackage.haskell.org/package/test-framework>+  --+  -- For more ways to run the tests, see "Test.SmallCheck.Drivers".+  Depth,+  smallCheck,++  -- * Main types and classes+  Testable,+  Property,+   ) where  import Test.SmallCheck.Property
Test/SmallCheck/Drivers.hs view
@@ -5,103 +5,66 @@ -- License   : BSD3 -- Maintainer: Roman Cheplyaka <roma@ro-che.info> ----- Functions to run SmallCheck tests.+-- You should only need this module if you wish to create your own way to+-- run SmallCheck tests --------------------------------------------------------------------+{-# LANGUAGE FlexibleContexts #-} module Test.SmallCheck.Drivers (-  smallCheck, smallCheckI, depthCheck, smallCheckPure+  smallCheck, smallCheckM, smallCheckWithHook,+  test,+  ppFailure,+  PropertyFailure(..), PropertySuccess(..), Argument, TestQuality(..)   ) where -import System.IO (stdout, hFlush) import Control.Monad (when) import Test.SmallCheck.Property---- | Run series of tests using depth bounds 0..d, stopping if any test fails,--- and print a summary report or a counter-example.-smallCheck :: Testable a => Depth -> a -> IO ()-smallCheck d = iterCheck 0 (Just d)+import Test.SmallCheck.Property.Result+import Text.Printf+import Data.IORef --- | Same as 'smallCheck', but test for values of depth d only-depthCheck :: Testable a => Depth -> a -> IO ()-depthCheck d = iterCheck d (Just d)+-- | A simple driver that runs the test in the 'IO' monad and prints the+-- results.+smallCheck :: Testable IO a => Depth -> a -> IO ()+smallCheck d a = do+  ((good, bad), mbEx) <- runTestWithStats d a+  let testsRun = good + bad+  case mbEx of+    Nothing -> do+      printf "Completed %d tests without failure.\n" $ testsRun+      when (bad > 0) $+        printf "But %d did not meet ==> condition.\n" $ bad+    Just x -> do+      printf "Failed test no. %d.\n" $ testsRun+      putStrLn $ ppFailure x --- | Interactive variant, asking the user whether testing should--- continue\/go deeper after a failure\/completed iteration.------ Example session:------ >haskell> smallCheckI prop_append1--- >Depth 0:--- >  Completed 1 test(s) without failure.--- >  Deeper? y--- >Depth 1:--- >  Failed test no. 5. Test values follow.--- >  [True]--- >  [True]--- >  Continue? n--- >  Deeper? n--- >haskell>-smallCheckI :: Testable a => a -> IO ()-smallCheckI = iterCheck 0 Nothing+runTestWithStats :: Testable IO a => Depth -> a -> IO ((Integer, Integer), Maybe PropertyFailure)+runTestWithStats d prop = do+  good <- newIORef 0+  bad <- newIORef 0 -iterCheck :: Testable a => Depth -> Maybe Depth -> a -> IO ()-iterCheck dFrom mdTo t = iter dFrom-  where-  iter d = do-    putStrLn ("Depth "++show d++":")-    let results = test t d-    ok <- check (mdTo==Nothing) 0 0 True results-    maybe (whenUserWishes "  Deeper" () $ iter (d+1))-          (\dTo -> when (ok && d < dTo) $ iter (d+1))-          mdTo+  let+    hook GoodTest = modifyIORef' good (+1)+    hook BadTest  = modifyIORef' bad  (+1) -check :: Bool -> Integer -> Integer -> Bool -> [TestCase] -> IO Bool-check i n x ok rs | null rs = do-  putStr ("  Completed "++show n++" test(s)")-  putStrLn (if ok then " without failure." else ".")-  when (x > 0) $-    putStrLn ("  But "++show x++" did not meet ==> condition.")-  return ok-check i n x ok (TestCase Inappropriate _ : rs) = do-  progressReport i n x-  check i (n+1) (x+1) ok rs-check i n x f (TestCase Pass _ : rs) = do-  progressReport i n x-  check i (n+1) x f rs-check i n x f (TestCase Fail args : rs) = do-  putStrLn ("  Failed test no. "++show (n+1)++". Test values follow.")-  mapM_ (putStrLn . ("  "++)) args-  ( if i then-      whenUserWishes "  Continue" False $ check i (n+1) x False rs-    else-      return False )+  r <- smallCheckWithHook d hook prop -whenUserWishes :: String -> a -> IO a -> IO a-whenUserWishes wish x action = do-  putStr (wish++"? ")-  hFlush stdout-  reply <- getLine-  ( if (null reply || reply=="y") then action-    else return x )+  goodN <- readIORef good+  badN  <- readIORef bad -progressReport :: Bool -> Integer -> Integer -> IO ()-progressReport i n x | n >= x = do-  when i $ ( putStr (n' ++ replicate (length n') '\b') >>-             hFlush stdout )-  where-  n' = show n+  return ((goodN, badN), r) --- | A pure analog of 'smallCheck'.+-- | Use this if: ----- If a counterexample is found, it is returned.+-- * You need to run a test in a monad different from 'IO' ----- Otherwise, a tuple of two numbers is returned, where the first number is the--- number of all test cases, and the second number is the number of test cases--- that did not satisfy the precondition.-smallCheckPure :: Testable a => Depth -> a -> Either [String] (Integer, Integer)-smallCheckPure d a = (foldr step Right $ concatMap (test a) [0..d]) (0,0)-  where-    step testRes rest (n, x) = n `seq` x `seq`-      case result testRes of-        Fail -> Left $ arguments testRes-        Pass ->          rest (n+1, x)-        Inappropriate -> rest (n+1, x+1)+-- * You need to analyse the results rather than just print them+smallCheckM :: Testable m a => Depth -> a -> m (Maybe PropertyFailure)+smallCheckM d a = smallCheckWithHook d (const $ return ()) a++-- | Like `smallCheckM`, but allows to specify a monadic hook that gets+-- executed after each test is run.+--+-- Useful for applications that want to report progress information to the+-- user.+smallCheckWithHook :: Testable m a => Depth -> (TestQuality -> m ()) -> a -> m (Maybe PropertyFailure)+smallCheckWithHook d hook a = runProperty d hook $ test a
Test/SmallCheck/Property.hs view
@@ -1,3 +1,5 @@+-- vim:fdm=marker:foldtext=foldtext()+ -------------------------------------------------------------------- -- | -- Module    : Test.SmallCheck.Property@@ -7,173 +9,322 @@ -- -- Properties and tools to construct them. ---------------------------------------------------------------------{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, TypeFamilies,+             ScopedTypeVariables #-} module Test.SmallCheck.Property (-  -- * Basic definitions-  TestCase(..),-  TestResult(..),-  resultIsOk,+  -- * Constructors+  forAll, exists, existsUnique, over, (==>), monadic, changeDepth, changeDepth1, -  Property, Depth, Testable(..),-  property, mkProperty,+  -- * Property's entrails+  Property, -  -- * Constructing tests-  (==>), exists, existsDeeperBy, exists1, exists1DeeperBy,-  -- ** Series- and list-based constructors-  -- | Combinators below can be used to explicitly specify the domain of-  -- quantification (as 'Series' or lists).-  ---  -- Hopefully, their meaning is evident from their names and types.-  forAll, forAllElem,-  thereExists, thereExistsElem,-  thereExists1, thereExists1Elem+  PropertySuccess(..), PropertyFailure(..), runProperty, TestQuality(..), Argument, Depth, Testable(..),   ) where  import Test.SmallCheck.Series+import Test.SmallCheck.SeriesMonad+import Test.SmallCheck.Property.Result+import Control.Monad+import Control.Monad.Logic+import Control.Monad.Reader+import Control.Applicative import Data.Typeable -data TestResult-    = Pass-    | Fail-    | Inappropriate-        -- ^ 'Inappropriate' means that the precondition of '==>'-        -- was not satisfied-data TestCase = TestCase { result :: TestResult, arguments :: [String] }+------------------------------+-- Property-related types+------------------------------+--{{{ --- | Wrapper type for 'Testable's-newtype Property = Property (Depth -> [TestCase])-  deriving Typeable+-- | The type of properties over the monad @m@+newtype Property m = Property { unProperty :: Reader (Env m) (PropertySeries m) } --- | Wrap a 'Testable' into a 'Property'-property :: Testable a => a -> Property-property = Property . test+data PropertySeries m =+  PropertySeries+    { searchExamples        :: Series m PropertySuccess+    , searchCounterExamples :: Series m PropertyFailure+    , searchClosest         :: Series m (Property m, [Argument])+    } --- | A lower-level way to create properties. Use 'property' if possible.+data Env m =+  Env+    { quantification :: Quantification+    , testHook :: TestQuality -> m ()+    }++data Quantification+  = Forall+  | Exists+  | ExistsUnique++data TestQuality+  = GoodTest+  | BadTest+  deriving (Eq, Ord, Enum, Show)++instance Typeable1 m => Typeable (Property m)+  where+    typeOf _ =+      mkTyConApp+        (mkTyCon3 "smallcheck" "Test.SmallCheck.Property" "Property")+        [typeOf (undefined :: m ())]++-- }}}++------------------------------------+-- Property runners and constructors+------------------------------------+--{{{++unProp :: Env t -> Property t -> PropertySeries t+unProp q (Property p) = runReader p q++runProperty+  :: Monad m+  => Depth+  -> (TestQuality -> m ())+  -> Property m+  -> m (Maybe PropertyFailure)+runProperty depth hook prop =+  (\l -> runLogicT l (\x _ -> return $ Just x) (return Nothing)) $+  runSeries depth $+  searchCounterExamples $+  flip runReader (Env Forall hook) $+  unProperty prop++atomicProperty :: Series m PropertySuccess -> Series m PropertyFailure -> PropertySeries m+atomicProperty s f =+  let prop = PropertySeries s f (pure (Property $ pure prop, []))+  in prop++makeAtomic :: Property m -> Property m+makeAtomic (Property prop) =+  Property $ flip fmap prop $ \ps ->+    atomicProperty (searchExamples ps) (searchCounterExamples ps)++-- | @'over' s $ \\x -> p x@ makes @x@ range over the 'Series' @s@ (by+-- default, all variables range over the 'series' for their types). ----- The argument is a function that produces the list of results given the depth--- of testing.-mkProperty :: (Depth -> [TestCase]) -> Property-mkProperty = Property+-- Note that, unlike the quantification operators, this affects only the+-- variable following the operator and not subsequent variables.+--+-- 'over' does not affect the quantification context.+over+  :: (Monad m, Show a, Testable m b)+  => Series m a -> (a -> b) -> Property m+over = testFunction --- | Anything of a 'Testable' type can be regarded as a \"test\"-class Testable a where-  test :: a -> Depth -> [TestCase]+-- | Execute a monadic test+monadic :: Testable m a => m a -> Property m+monadic a =+  Property $ reader $ \env -> -instance Testable Bool where-  test b _ = [TestCase (boolToResult b) []]+    let pair = unProp env . freshContext <$> lift a in -instance (Serial a, Show a, Testable b) => Testable (a->b) where-  test f = f' where Property f' = forAll series f+    atomicProperty+      (searchExamples =<< pair)+      (searchCounterExamples =<< pair) -instance Testable Property where-  test (Property f) d = f d+-- }}} -forAll :: (Show a, Testable b) => Series a -> (a->b) -> Property-forAll xs f = Property $ \d ->-  [ r{arguments = show x : arguments r}-  | x <- xs d, r <- test (f x) d ]+-------------------------------+-- Testable class and instances+-------------------------------+-- {{{ -forAllElem :: (Show a, Testable b) => [a] -> (a->b) -> Property-forAllElem xs = forAll (const xs)+-- | Class of tests that can be run in a monad. For pure tests, it is+-- recommended to keep their types polymorphic in @m@ rather than+-- specialising it to 'Identity'.+class Monad m => Testable m a where+  test :: a -> Property m -existence :: (Show a, Testable b) => Bool -> Series a -> (a->b) -> Property-existence u xs f = Property existenceDepth-  where-  existenceDepth d = [ TestCase (boolToResult valid) arguments ]-    where-    witnesses = [ show x | x <- xs d, all (resultIsOk . result) (test (f x) d) ]-    valid     = enough witnesses-    enough    = if u then unique else (not . null)-    arguments = if valid then []-                else if null witnesses then ["non-existence"]-                else "non-uniqueness" : take 2 witnesses+instance Monad m => Testable m Bool where+  test b = Property $ reader $ \env ->+    let+      success = do+        lift $ testHook env GoodTest+        if b then return PropertyTrue else mzero+      failure = PropertyFalse <$ lnot success+    in atomicProperty success failure -unique :: [a] -> Bool-unique [_] = True-unique  _  = False+instance (Serial m a, Show a, Testable m b) => Testable m (a->b) where+  test = testFunction series --- | Return 'False' iff the result is 'Fail'-resultIsOk :: TestResult -> Bool-resultIsOk r =-    case r of-        Fail -> False-        Pass -> True-        Inappropriate -> True+instance (Monad m, m ~ n) => Testable n (Property m) where+  test = id -boolToResult :: Bool -> TestResult-boolToResult b = if b then Pass else Fail+testFunction+  :: (Monad m, Show a, Testable m b)+  => Series m a -> (a -> b) -> Property m+testFunction s f = Property $ reader $ \env ->+  let+    closest = do+      x <- s+      (p, args) <- searchClosest $ unProp env $ test $ f x+      return (p, show x : args)+  in -thereExists :: (Show a, Testable b) => Series a -> (a->b) -> Property-thereExists = existence False+  case quantification env of+    Forall -> PropertySeries success failure closest+      -- {{{+      where+        failure = do+          x <- s+          failure <- searchCounterExamples $ unProp env $ test $ f x+          let arg = show x+          return $+            case failure of+              CounterExample args etc -> CounterExample (arg:args) etc+              _ -> CounterExample [arg] failure -thereExists1 :: (Show a, Testable b) => Series a -> (a->b) -> Property-thereExists1 = existence True+        success = PropertyTrue <$ lnot failure+      -- }}} -thereExistsElem :: (Show a, Testable b) => [a] -> (a->b) -> Property-thereExistsElem xs = thereExists (const xs)+    Exists -> PropertySeries success failure closest+      -- {{{+      where+        success = do+          x <- s+          s <- searchExamples $ unProp env $ test $ f x+          let arg = show x -thereExists1Elem :: (Show a, Testable b) => [a] -> (a->b) -> Property-thereExists1Elem xs = thereExists1 (const xs)+          return $+            case s of+              Exist args etc -> Exist (arg:args) etc+              _ -> Exist [arg] s --- | @'exists' p@ holds iff it is possible to find an argument @a@ (within the--- depth constraints!) satisfying the predicate @p@-exists :: (Show a, Serial a, Testable b) => (a->b) -> Property-exists = thereExists series+        failure = NotExist <$ lnot success+      -- }}} --- | Like 'exists', but additionally require the uniqueness of the--- argument satisfying the predicate-exists1 :: (Show a, Serial a, Testable b) => (a->b) -> Property-exists1 = thereExists1 series+    ExistsUnique -> PropertySeries success failure closest+      -- {{{+      where+        search = atMost 2 $ do+          (prop, args) <- closest+          ex <- once $ searchExamples $ unProp env $ test prop+          return (args, ex) --- | The default testing of existentials is bounded by the same depth as their--- context. This rule has important consequences. Just as a universal property--- may be satisfied when the depth bound is shallow but fail when it is deeper,--- so the reverse may be true for an existential property. So when testing--- properties involving existentials it may be appropriate to try deeper testing--- after a shallow failure. However, sometimes the default same-depth-bound--- interpretation of existential properties can make testing of a valid property--- fail at all depths. Here is a contrived but illustrative example:------ >prop_append1 :: [Bool] -> [Bool] -> Property--- >prop_append1 xs ys = exists $ \zs -> zs == xs++ys------ 'existsDeeperBy' transforms the depth bound by a given @'Depth' -> 'Depth'@ function:------ >prop_append2 :: [Bool] -> [Bool] -> Property--- >prop_append2 xs ys = existsDeeperBy (*2) $ \zs -> zs == xs++ys-existsDeeperBy :: (Show a, Serial a, Testable b) => (Depth->Depth) -> (a->b) -> Property-existsDeeperBy f = thereExists (series . f)+        success =+          search >>=+            \examples ->+              case examples of+                [(x,s)] -> return $ ExistUnique x s+                _ -> mzero --- | Like 'existsDeeperBy', but additionally require the uniqueness of the--- argument satisfying the predicate-exists1DeeperBy :: (Show a, Serial a, Testable b) => (Depth->Depth) -> (a->b) -> Property-exists1DeeperBy f = thereExists1 (series . f)+        failure =+          search >>=+            \examples ->+              case examples of+                [] -> return NotExist+                (x1,s1):(x2,s2):_ -> return $ AtLeastTwo x1 s1 x2 s2+                _ -> mzero+      -- }}} -infixr 0 ==>+atMost :: MonadLogic m => Int -> m a -> m [a]+atMost n m+  | n <= 0 = return []+  | otherwise = do+      m' <- msplit m+      case m' of+        Nothing -> return []+        Just (x,rest) ->+          (x:) `liftM` atMost (n-1) rest --- | The '==>' operator can be used to express a--- restricting condition under which a property should hold. For example,--- testing a propositional-logic module (see examples/logical), we might--- define:+-- }}}++------------------------------+-- Test constructors+------------------------------+-- {{{++quantify :: Quantification -> Property m -> Property m+quantify q (Property a) =+  makeAtomic $ Property $ local (\env -> env { quantification = q }) a++freshContext :: Testable m a => a -> Property m+freshContext = forAll++-- | Set the universal quantification context+forAll :: Testable m a => a -> Property m+forAll = quantify Forall . test++-- | Set the existential quantification context+exists :: Testable m a => a -> Property m+exists = quantify Exists . test++-- | Set the uniqueness quantification context. ----- >prop_tautEval :: Proposition -> Environment -> Property--- >prop_tautEval p e =--- >  tautology p ==> eval p e+-- Bear in mind that ∃! (x, y): p x y is not the same as ∃! x: ∃! y: p x y. ----- But here is an alternative definition:+-- For example, ∃! x: ∃! y: |x| = |y| is true (it holds only when x=0), but ∃! (x,y): |x| = |y| is false (there are many such pairs). ----- >prop_tautEval :: Proposition -> Property--- >prop_taut p =--- >  tautology p ==> \e -> eval p e+-- As is customary in mathematics,+-- @'existsUnique' $ \\x y -> p x y@ is equivalent to+-- @'existsUnique' $ \\(x,y) -> p x y@ and not to+-- @'existsUnique' $ \\x -> 'existsUnique' $ \\y -> p x y@+-- (the latter, of course, may be explicitly written when desired). ----- The first definition generates p and e for each test, whereas the--- second only generates e if the tautology p holds.+-- That is, all the variables affected by the same uniqueness context are+-- quantified simultaneously as a tuple.+existsUnique :: Testable m a => a -> Property m+existsUnique = quantify ExistsUnique . test++-- | The '==>' operator can be used to express a restricting condition+-- under which a property should hold. It corresponds to implication in the+-- classical logic. ----- The second definition is far better as the test-space is--- reduced from PE to T'+TE where P, T, T' and E are the numbers of--- propositions, tautologies, non-tautologies and environments.-(==>) :: Testable a => Bool -> a -> Property-True ==>  x = Property (test x)-False ==> x = Property (const [nothing])-    where-    nothing = TestCase { result = Inappropriate, arguments = [] }+-- Note that '==>' resets the quantification context for its operands to+-- the default (universal).+infixr 0 ==>+(==>) :: (Testable m c, Testable m a) => c -> a -> Property m+cond ==> prop = Property $ do+  env <- ask++  let+    counterExample = once $ searchCounterExamples $ unProp env' $ freshContext cond+      -- NB: we do not invoke the test hook in the antecedent+      where env' = env { testHook = const $ return () }++    consequent = unProp env $ freshContext prop++    badTestHook = lift $ testHook env BadTest++    success =+      ifte counterExample+        -- then+        (\ex -> do+          badTestHook+          return $ Vacuously ex+        )+        -- else+        (searchExamples consequent)++    failure =+      ifte counterExample+        -- then+        (const $ do+          lift $ testHook env BadTest+          mzero+        )+        -- else+        (searchCounterExamples consequent)++  return $ atomicProperty success failure++-- | Run property with a modified depth. Affects all quantified variables+-- in the property.+changeDepth :: Testable m a => (Depth -> Depth) -> a -> Property m+changeDepth modifyDepth a = Property (changeDepthPS <$> unProperty (test a))+  where+    changeDepthPS (PropertySeries ss sf sc) =+      PropertySeries+        (localDepth modifyDepth ss)+        (localDepth modifyDepth sf)+        ((\(prop, args) -> (changeDepth modifyDepth prop, args)) <$>+          localDepth modifyDepth sc)++-- | Quantify the function's argument over its 'series', but adjust the+-- depth. This doesn't affect any subsequent variables.+changeDepth1 :: (Show a, Serial m a, Testable m b) => (Depth -> Depth) -> (a -> b) -> Property m+changeDepth1 modifyDepth = over $ localDepth modifyDepth series++-- }}}
+ Test/SmallCheck/Property/Result.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, DefaultSignatures #-}+module Test.SmallCheck.Property.Result+  ( PropertySuccess(..)+  , PropertyFailure(..)+  , ppFailure+  , Argument+  ) where++import Text.PrettyPrint++type Argument = String++data PropertySuccess+  = Exist [Argument] PropertySuccess+  | ExistUnique [Argument] PropertySuccess+  | PropertyTrue+  | Vacuously PropertyFailure+  deriving (Eq, Show)++data PropertyFailure+  = NotExist+  | AtLeastTwo [Argument] PropertySuccess [Argument] PropertySuccess+  | CounterExample [Argument] PropertyFailure+  | PropertyFalse+  deriving (Eq, Show)++class Pretty a where+  pretty :: a -> Doc++instance Pretty PropertyFailure where+  pretty NotExist = text "argument does not exist"+  pretty (AtLeastTwo args1 s1 args2 s2) =+    text "there are at least two" <+>+    plural args1 empty (text "sets of") <+>+    text "arguments satisfying the property:" $$+      formatExample args1 s1 $$ formatExample args2 s2+    where+    formatExample args s = nest ind $ text "for" <+> prettyArgs args </> (pretty s)+  pretty (CounterExample args f) =+    text "there" <+>+    text (plural args "exists" "exist") <+>+    prettyArgs args <+>+    text "such that"+    </> (pretty f)+  pretty PropertyFalse = text "condition is false"++instance Pretty PropertySuccess where+  pretty PropertyTrue = text "condition is true"+  pretty (Exist       args s) = existsMsg False args s+  pretty (ExistUnique args s) = existsMsg True args s+  pretty (Vacuously s) = text "property is vacuously true because" </> pretty s++ind :: Int+ind = 2++infixl 5 </>+(</>) :: Doc -> Doc -> Doc+a </> b = a $+$ nest ind b++prettyArgs :: [Argument] -> Doc+prettyArgs = hsep . map text++existsMsg :: Pretty a => Bool -> [Argument] -> a -> Doc+existsMsg unique args s =+  text "there" <+> text (plural args "exists" "exist") <+>+  (if unique then text "unique" else empty) <+>+  prettyArgs args <+>+  text "such that" </>+  pretty s++plural :: [a] -> b -> b -> b+plural lst sing pl =+  case lst of+    _:_:_ -> pl+    _ -> sing++ppFailure :: PropertyFailure -> String+ppFailure = render . pretty
Test/SmallCheck/Series.hs view
@@ -1,3 +1,5 @@+-- vim:fdm=marker:foldtext=foldtext()+ -------------------------------------------------------------------- -- | -- Module    : Test.SmallCheck.Series@@ -5,28 +7,58 @@ -- License   : BSD3 -- Maintainer: Roman Cheplyaka <roma@ro-che.info> ----- Generation of test data.+-- You need this module if you want to generate test values of your own+-- types.+--+-- You'll typically need the following extensions:+--+-- >{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+--+-- SmallCheck itself defines data generators for all the data types used+-- by the "Prelude".+--+-- In order to generate values and functions of your own types, you need+-- to make them instances of 'Serial' (for values) and 'CoSerial' (for+-- functions). There are two main ways to do so: using Generics or writing+-- the instances by hand. ---------------------------------------------------------------------{-# LANGUAGE CPP #-} -#ifdef GENERICS-{-# LANGUAGE DefaultSignatures-           , FlexibleContexts-           , TypeOperators-           , TypeSynonymInstances-           , FlexibleInstances-  #-}-#endif+{-# LANGUAGE CPP, RankNTypes, MultiParamTypeClasses, FlexibleInstances,+             GeneralizedNewtypeDeriving, FlexibleContexts #-}+-- The following is needed for generic instances+{-# LANGUAGE DefaultSignatures, FlexibleContexts, TypeOperators,+             TypeSynonymInstances, FlexibleInstances #-}  module Test.SmallCheck.Series (-  -- * Basic definitions-  Depth, Series, Serial(..),+  -- {{{+  -- * Generic instances+  -- | The easiest way to create the necessary instances is to use GHC+  -- generics (available starting with GHC 7.2.1).+  --+  -- Here's a complete example:+  --+  -- >{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+  -- >{-# LANGUAGE DeriveGeneric #-}+  -- >+  -- >import Test.SmallCheck.Series+  -- >import GHC.Generics+  -- >+  -- >data Tree a = Null | Fork (Tree a) a (Tree a)+  -- >    deriving Generic+  -- >+  -- >instance Serial m a => Serial m (Tree a)+  --+  -- Here we enable the @DeriveGeneric@ extension which allows to derive 'Generic'+  -- instance for our data type. Then we declare that @Tree a@ is an instance of+  -- 'Serial', but do not provide any definitions. This causes GHC to use the+  -- default definitions that use the 'Generic' instance.+  --+  -- One minor limitation of generic instances is that there's currently no+  -- way to distinguish newtypes and datatypes. Thus, newtype constructors+  -- will also count as one level of depth.    -- * Data Generators-  -- | SmallCheck itself defines data generators for all the data types used-  -- by the Prelude.-  ---  -- Writing SmallCheck generators for application-specific types is+  -- | Writing 'Serial' instances for application-specific types is   -- straightforward. You need to define a 'series' generator, typically using   -- @consN@ family of generic combinators where N is constructor arity.   --@@ -34,21 +66,17 @@   --   -- >data Tree a = Null | Fork (Tree a) a (Tree a)   -- >-  -- >instance Serial a => Serial (Tree a) where+  -- >instance Serial m a => Serial m (Tree a) where   -- >  series = cons0 Null \/ cons3 Fork   ---  -- The default interpretation of depth for datatypes is the depth of nested-  -- construction: constructor functions, including those for newtypes, build-  -- results with depth one greater than their deepest argument.  But this-  -- default can be over-ridden by composing a @consN@ application with an-  -- application of 'depth', like this:+  -- For newtypes use 'newtypeCons' instead of 'cons1'.+  -- The difference is that 'cons1' is counts as one level of depth, while+  -- 'newtypeCons' doesn't affect the depth.   --   -- >newtype Light a = Light a   -- >-  -- >instance Serial a => Serial (Light a) where-  -- >  series = cons1 Light . depth 0-  ---  -- The depth of @Light x@ is just the depth of @x@.+  -- >instance Serial m a => Serial m (Light a) where+  -- >  series = newtypeCons Light    -- ** What does consN do, exactly? @@ -63,25 +91,38 @@   -- where @x_i@ ranges over all values of type @t_i@ of depth up to @d-1@   -- (as defined by the 'series' functions for @t_i@).   --+  -- @consN@ functions also ensure that x_i are enumerated in the+  -- breadth-first order. Thus, combinations of smaller depth come first+  -- (assuming the same is true for @t_i@).+  --   -- If @d <= 0@, no values are produced. -  cons0, cons1, cons2, cons3, cons4,+  cons0, cons1, cons2, cons3, cons4, newtypeCons,   -- * Function Generators -  -- | To generate functions of an application-specific argument type-  -- requires a second method 'coseries'.  Again there is a standard-  -- pattern, this time using the altsN combinators where again N is-  -- constructor arity.  Here are Tree and Light instances:+  -- | To generate functions of an application-specific argument type,+  -- make the type an instance of 'CoSerial'.   ---  -- >coseries rs d = [ \t -> case t of-  -- >                        Null         -> z-  -- >                        Fork t1 x t2 -> f t1 x t2-  -- >                |  z <- alts0 rs d ,-  -- >                   f <- alts3 rs d ]-  -- >-  -- >coseries rs d = [ \l -> case l of-  -- >                        Light x -> f x-  -- >                |  f <- (alts1 rs . depth 0) d ]+  -- Again there is a standard pattern, this time using the altsN+  -- combinators where again N is constructor arity.  Here are @Tree@ and+  -- @Light@ instances:+  --+  --+  -- >instance CoSerial m a => CoSerial m (Tree a) where+  -- >  coseries rs =+  -- >    alts0 rs >>- \z ->+  -- >    alts3 rs >>- \f ->+  -- >    return $ \t ->+  -- >      case t of+  -- >        Null -> z+  -- >        Fork t1 x t2 -> f t1 x t2+  --+  -- >instance CoSerial m a => CoSerial m (Light a) where+  -- >  coseries rs =+  -- >    newtypeAlts rs >>- \f ->+  -- >    return $ \l ->+  -- >      case l of+  -- >        Light x -> f x    -- ** What does altsN do, exactly? @@ -93,342 +134,405 @@   --   -- >t_1 -> ... -> t_N -> t   ---  -- If @d <= 0@, these are constant functions, one for each value of @s 0@.+  -- If @d <= 0@, these are constant functions, one for each value produced+  -- by @s@.   ---  -- If @d > 0@, these functions inspect each of their arguments up to depth+  -- If @d > 0@, these functions inspect each of their arguments up to the depth   -- @d-1@ (as defined by the 'coseries' functions for the corresponding-  -- types) and return values given by @s d@.--  alts0, alts1, alts2, alts3, alts4,+  -- types) and return values produced by @s@. -  -- * Automated Derivation of Generators+  alts0, alts1, alts2, alts3, alts4, newtypeAlts, -  -- | For small examples, Series instances are easy enough to define by hand,-  -- following the above patterns.  But for programs with many or large data-  -- type definitions, automatic derivation using a tool such as \"derive\"-  -- is a better option. For example, the following command-line appends to-  -- Prog.hs the Series instances for all data types defined there.-  ---  -- >$ derive Prog.hs -d Serial --append+  -- * Basic definitions+  Depth, Series, Serial(..), CoSerial(..), -  -- ** Using GHC Generics-  -- | For GHC users starting from GHC 7.2.1 there's also an option to use GHC's-  -- Generics to get 'Serial' instance for free.-  ---  -- Example:-  ---  -- >{-# LANGUAGE DeriveGeneric #-}-  -- >import Test.SmallCheck-  -- >import GHC.Generics-  -- >-  -- >data Tree a = Null | Fork (Tree a) a (Tree a)-  -- >    deriving Generic-  -- >instance Serial a => Serial (Tree a)-  ---  -- Here we enable the @DeriveGeneric@ extension which allows to derive 'Generic'-  -- instance for our data type. Then we declare that @Tree a@ is an instance of-  -- 'Serial', but do not provide any definitions. This causes GHC to use the-  -- default definitions that use the 'Generic' instance.+  -- * Convenient wrappers+  Positive(..), NonNegative(..),    -- * Other useful definitions-  (\/), (><),-  N(..), Nat, Natural,-  depth+  (\/), (><), (<~>), (>>-),+  localDepth,+  decDepth,+  getDepth,+  generate,+  list+  -- }}}   ) where -import Data.List (intersperse)--#ifdef GENERICS+import Control.Monad.Logic+import Control.Monad.Reader+import Control.Applicative+import Control.Monad.Identity+import Data.List+import Test.SmallCheck.SeriesMonad import GHC.Generics-import Data.DList (DList, toList, fromList)-import Data.Monoid (mempty, mappend)-#endif --- | Maximum depth of generated test values------ For data values, it is the depth of nested constructor applications.------ For functional values, it is both the depth of nested case analysis--- and the depth of results.-type Depth = Int+------------------------------+-- Main types and classes+------------------------------+--{{{ --- | 'Series' is a function from the depth to a finite list of values.------ If @s@ is a 'Series', @s n@ is expected to yield values of depth up to @n@.------ (In particular, @series d@ is expected to be a subset of @series (d+1)@.)-type Series a = Depth -> [a]+class Monad m => Serial m a where+  series   :: Series m a +  default series :: (Generic a, GSerial m (Rep a)) => Series m a+  series = to <$> gSeries++class Monad m => CoSerial m a where+  -- | A proper 'coseries' implementation should pass the depth unchanged to+  -- its first argument. Doing otherwise will make enumeration of curried+  -- functions non-uniform in their arguments.+  coseries :: Series m b -> Series m (a->b)++  default coseries :: (Generic a, GCoSerial m (Rep a)) => Series m b -> Series m (a->b)+  coseries rs = (. from) <$> gCoseries rs++-- }}}++------------------------------+-- Helper functions+------------------------------+-- {{{++-- | A simple series specified by a function from depth to the list of+-- values up to that depth.+generate :: (Depth -> [a]) -> Series m a+generate f = do+  d <- getDepth+  msum $ map return $ f d++suchThat :: Series m a -> (a -> Bool) -> Series m a+suchThat s p = s >>= \x -> if p x then pure x else empty++-- | Return the list of values generated by a 'Series'. Useful for+-- debugging 'Serial' instances.+list :: Depth -> Series Identity a -> [a]+list d s = runIdentity $ observeAllT $ runSeries d s+ -- | Sum (union) of series infixr 7 \/-(\/) :: Series a -> Series a -> Series a-s1 \/ s2 = \d -> s1 d ++ s2 d+(\/) :: Monad m => Series m a -> Series m a -> Series m a+(\/) = interleave  -- | Product of series infixr 8 ><-(><) :: Series a -> Series b -> Series (a,b)-s1 >< s2 = \d -> [(x,y) | x <- s1 d, y <- s2 d]+(><) :: Monad m => Series m a -> Series m b -> Series m (a,b)+a >< b = (,) <$> a <~> b -class Serial a where-  series   :: Series a-  -- | A proper 'coseries' implementation should pass the depth unchanged to-  -- its first argument. Doing otherwise will make enumeration of curried-  -- functions non-uniform in their arguments.-  coseries :: Series b -> Series (a->b)+-- | Fair version of 'ap' and '<*>'+infixl 4 <~>+(<~>) :: Monad m => Series m (a -> b) -> Series m a -> Series m b+a <~> b = a >>- (<$> b) -#ifdef GENERICS-  default series :: (Generic a, GSerial (Rep a)) => Series a-  series = map to . gSeries+uncurry3 :: (a->b->c->d) -> ((a,b,c)->d)+uncurry3 f (x,y,z) = f x y z -  default coseries :: (Generic a, GSerial (Rep a)) => Series b -> Series (a->b)-  coseries rs = map (. from) . gCoseries rs+uncurry4 :: (a->b->c->d->e) -> ((a,b,c,d)->e)+uncurry4 f (w,x,y,z) = f w x y z -class GSerial f where-  gSeries   :: Series (f a)-  gCoseries :: Series b -> Series (f a -> b)+-- | Query the current depth+getDepth :: Series m Depth+getDepth = Series ask -instance GSerial f => GSerial (M1 i c f) where-  gSeries      = map M1 . gSeries-  gCoseries rs = map (. unM1) . gCoseries rs-  {-# INLINE gSeries #-}-  {-# INLINE gCoseries #-}+-- | Run a series with a modified depth+localDepth :: (Depth -> Depth) -> Series m a -> Series m a+localDepth f (Series a) = Series $ local f a -instance Serial c => GSerial (K1 i c) where-  gSeries      = map K1 . series-  gCoseries rs = map (. unK1) . coseries rs-  {-# INLINE gSeries #-}-  {-# INLINE gCoseries #-}+-- | Run a 'Series' with the depth decreased by 1.+--+-- If the current depth is less or equal to 0, the result is 'mzero'.+decDepth :: Series m a -> Series m a+decDepth a = do+  checkDepth+  localDepth (subtract 1) a -instance GSerial U1 where-  gSeries        = cons0 U1-  gCoseries rs d = [\U1 -> b | b <- rs d]-  {-# INLINE gSeries #-}-  {-# INLINE gCoseries #-}+checkDepth :: Series m ()+checkDepth = do+  d <- getDepth+  guard $ d > 0 -instance (GSerial a, GSerial b) => GSerial (a :*: b) where-  gSeries    d = [x :*: y | x <- gSeries d, y <- gSeries d]-  gCoseries rs = map uncur . gCoseries (gCoseries rs)-      where-        uncur f (x :*: y) = f x y-  {-# INLINE gSeries #-}-  {-# INLINE gCoseries #-}+constM :: Monad m => m b -> m (a -> b)+constM = liftM const -instance (GSerialSum a, GSerialSum b) => GSerial (a :+: b) where-  gSeries   = toList . gSeriesSum-  gCoseries = gCoseriesSum-  {-# INLINE gSeries #-}-  {-# INLINE gCoseries #-}+-- | If the current depth is 0, evaluate the first argument. Otherwise,+-- evaluate the second argument with decremented depth.+decDepthChecked :: Series m a -> Series m a -> Series m a+decDepthChecked b r = do+  d <- getDepth+  if d == 0+    then b+    else decDepth r -class GSerialSum f where-  gSeriesSum   :: DSeries (f a)-  gCoseriesSum :: Series b -> Series (f a -> b)+unwind :: MonadLogic m => m a -> m [a]+unwind a =+  msplit a >>=+  maybe (return []) (\(x,a') -> (x:) `liftM` unwind a') -type DSeries a = Depth -> DList a+-- }}} -instance (GSerialSum a, GSerialSum b) => GSerialSum (a :+: b) where-  gSeriesSum      d = fmap L1 (gSeriesSum d) `mappend` fmap R1 (gSeriesSum d)-  gCoseriesSum rs d = [ \e -> case e of-                                L1 x -> f x-                                R1 y -> g y-                      | f <- gCoseriesSum rs d-                      , g <- gCoseriesSum rs d-                      ]-  {-# INLINE gSeriesSum #-}-  {-# INLINE gCoseriesSum #-}+------------------------------+-- cons* and alts* functions+------------------------------+-- {{{ -instance GSerial f => GSerialSum (C1 c f) where-  gSeriesSum      d | d > 0     = fromList $ gSeries (d-1)-                    | otherwise = mempty-  gCoseriesSum rs d | d > 0     = gCoseries rs (d-1)-                    | otherwise = [\_ -> x | x <- rs d]-  {-# INLINE gSeriesSum #-}-  {-# INLINE gCoseriesSum #-}-#endif+cons0 :: a -> Series m a+cons0 x = decDepth $ pure x -instance Serial () where-  series      _ = [()]-  coseries rs d = [ \() -> b-                  | b <- rs d ]+cons1 :: Serial m a => (a->b) -> Series m b+cons1 f = decDepth $ f <$> series -instance Serial Int where-  series      d = [(-d)..d]-  coseries rs d = [ \i -> if i > 0 then f (N (i - 1))-                          else if i < 0 then g (N (abs i - 1))-                          else z-                  | z <- alts0 rs d, f <- alts1 rs d, g <- alts1 rs d ]+-- | Same as 'cons1', but preserves the depth.+newtypeCons :: Serial m a => (a->b) -> Series m b+newtypeCons f = f <$> series -instance Serial Integer where-  series      d = [ toInteger (i :: Int)-                  | i <- series d ]-  coseries rs d = [ f . (fromInteger :: Integer->Int)-                  | f <- coseries rs d ]+cons2 :: (Serial m a, Serial m b) => (a->b->c) -> Series m c+cons2 f = decDepth $ f <$> series <~> series --- | 'N' is a wrapper for 'Integral' types that causes only non-negative values--- to be generated. Generated functions of type @N a -> b@ do not distinguish--- different negative values of @a@.------ See also 'Nat' and 'Natural'.-newtype N a = N a-              deriving (Eq, Ord)+cons3 :: (Serial m a, Serial m b, Serial m c) =>+         (a->b->c->d) -> Series m d+cons3 f = decDepth $+  f <$> series+    <~> series+    <~> series -instance Show a => Show (N a) where-  show (N i) = show i+cons4 :: (Serial m a, Serial m b, Serial m c, Serial m d) =>+         (a->b->c->d->e) -> Series m e+cons4 f = decDepth $+  f <$> series+    <~> series+    <~> series+    <~> series -instance (Integral a, Serial a) => Serial (N a) where-  series      d = map N [0..d']-                  where-                  d' = fromInteger (toInteger d)-  coseries rs d = [ \(N i) -> if i > 0 then f (N (i - 1))-                              else z-                  | z <- alts0 rs d, f <- alts1 rs d ]+alts0 :: Series m a -> Series m a+alts0 s = s -type Nat = N Int-type Natural = N Integer+alts1 :: (Monad m, CoSerial m a) => Series m b -> Series m (a->b)+alts1 rs =+  decDepthChecked (constM rs) (coseries rs) -instance Serial Float where-  series     d = [ encodeFloat sig exp-                 | (sig,exp) <- series d,-                   odd sig || sig==0 && exp==0 ]-  coseries rs d = [ f . decodeFloat-                  | f <- coseries rs d ]+alts2+  :: (CoSerial m a, CoSerial m b)+  => Series m c -> Series m (a->b->c)+alts2 rs =+  decDepthChecked+    (constM $ constM rs)+    (coseries $ coseries rs) -instance Serial Double where-  series      d = [ frac (x :: Float)-                  | x <- series d ]-  coseries rs d = [ f . (frac :: Double->Float)-                  | f <- coseries rs d ]+alts3 ::  (CoSerial m a, CoSerial m b, CoSerial m c) =>+            Series m d -> Series m (a->b->c->d)+alts3 rs =+  decDepthChecked+    (constM $ constM $ constM rs)+    (coseries $ coseries $ coseries rs) -frac :: (Real a, Fractional a, Real b, Fractional b) => a -> b-frac = fromRational . toRational+alts4 ::  (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d) =>+            Series m e -> Series m (a->b->c->d->e)+alts4 rs =+  decDepthChecked+    (constM $ constM $ constM $ constM rs)+    (coseries $ coseries $ coseries $ coseries rs) -instance Serial Char where-  series      d = take (d+1) ['a'..'z']-  coseries rs d = [ \c -> f (N (fromEnum c - fromEnum 'a'))-                  | f <- coseries rs d ]+-- | Same as 'alts1', but preserves the depth.+newtypeAlts :: (Monad m, CoSerial m a) => Series m b -> Series m (a->b)+newtypeAlts = coseries -instance (Serial a, Serial b) =>-         Serial (a,b) where-  series      = series >< series-  coseries rs = map uncurry . (coseries $ coseries rs)+-- }}} -instance (Serial a, Serial b, Serial c) =>-         Serial (a,b,c) where-  series      = \d -> [(a,b,c) | (a,(b,c)) <- series d]-  coseries rs = map uncurry3 . (coseries $ coseries $ coseries rs)+------------------------------+-- Generic instances+------------------------------+-- {{{ -instance (Serial a, Serial b, Serial c, Serial d) =>-         Serial (a,b,c,d) where-  series      = \d -> [(a,b,c,d) | (a,(b,(c,d))) <- series d]-  coseries rs = map uncurry4 . (coseries $ coseries $ coseries $ coseries rs)+class GSerial m f where+  gSeries :: Series m (f a)+class GCoSerial m f where+  gCoseries :: Series m b -> Series m (f a -> b) -uncurry3 :: (a->b->c->d) -> ((a,b,c)->d)-uncurry3 f (x,y,z) = f x y z+instance GSerial m f => GSerial m (M1 i c f) where+  gSeries = M1 <$> gSeries+  {-# INLINE gSeries #-}+instance GCoSerial m f => GCoSerial m (M1 i c f) where+  gCoseries rs = (. unM1) <$> gCoseries rs+  {-# INLINE gCoseries #-} -uncurry4 :: (a->b->c->d->e) -> ((a,b,c,d)->e)-uncurry4 f (w,x,y,z) = f w x y z+instance Serial m c => GSerial m (K1 i c) where+  gSeries = K1 <$> series+  {-# INLINE gSeries #-}+instance CoSerial m c => GCoSerial m (K1 i c) where+  gCoseries rs = (. unK1) <$> coseries rs+  {-# INLINE gCoseries #-} -cons0 ::-         a -> Series a-cons0 c _ = [c]+instance GSerial m U1 where+  gSeries = cons0 U1+  {-# INLINE gSeries #-}+instance GCoSerial m U1 where+  gCoseries rs = constM rs+  {-# INLINE gCoseries #-} -cons1 :: Serial a =>-         (a->b) -> Series b-cons1 c d = [c z | d > 0, z <- series (d-1)]+instance (Monad m, GSerial m a, GSerial m b) => GSerial m (a :*: b) where+  gSeries = (:*:) <$> gSeries <~> gSeries+  {-# INLINE gSeries #-}+instance (Monad m, GCoSerial m a, GCoSerial m b) => GCoSerial m (a :*: b) where+  gCoseries rs = uncur <$> gCoseries (gCoseries rs)+      where+        uncur f (x :*: y) = f x y+  {-# INLINE gCoseries #-} -cons2 :: (Serial a, Serial b) =>-         (a->b->c) -> Series c-cons2 c d = [c y z | d > 0, (y,z) <- series (d-1)]+instance (Monad m, GSerial m a, GSerial m b) => GSerial m (a :+: b) where+  gSeries = (L1 <$> gSeries) `interleave` (R1 <$> gSeries)+  {-# INLINE gSeries #-}+instance (Monad m, GCoSerial m a, GCoSerial m b) => GCoSerial m (a :+: b) where+  gCoseries rs =+    gCoseries rs >>- \f ->+    gCoseries rs >>- \g ->+    return $+    \e -> case e of+      L1 x -> f x+      R1 y -> g y+  {-# INLINE gCoseries #-} -cons3 :: (Serial a, Serial b, Serial c) =>-         (a->b->c->d) -> Series d-cons3 c d = [c x y z | d > 0, (x,y,z) <- series (d-1)]+-- }}} -cons4 :: (Serial a, Serial b, Serial c, Serial d) =>-         (a->b->c->d->e) -> Series e-cons4 c d = [c w x y z | d > 0, (w,x,y,z) <- series (d-1)]+------------------------------+-- Instances for basic types+------------------------------+-- {{{+instance Monad m => Serial m () where+  series = return ()+instance Monad m => CoSerial m () where+  coseries rs = constM rs -alts0 ::  Series a ->-            Series a-alts0 as d = as d+instance Monad m => Serial m Int where+  series =+    generate (\d -> if d >= 0 then pure 0 else empty) <|>+      nats `interleave` (fmap negate nats)+    where+      nats = generate $ \d -> [1..d] -alts1 ::  Serial a =>-            Series b -> Series (a->b)-alts1 bs d = if d > 0 then coseries bs (dec d)-             else [\_ -> x | x <- bs d]+instance Monad m => CoSerial m Int where+  coseries rs =+    alts0 rs >>- \z ->+    alts1 rs >>- \f ->+    alts1 rs >>- \g ->+    return $ \i -> case () of { _+      | i > 0 -> f (N (i - 1))+      | i < 0 -> g (N (abs i - 1))+      | otherwise -> z+    } -alts2 ::  (Serial a, Serial b) =>-            Series c -> Series (a->b->c)-alts2 cs d = if d > 0 then coseries (coseries cs) (dec d)-             else [\_ _ -> x | x <- cs d]+instance Monad m => Serial m Integer where+  series = (toInteger :: Int -> Integer) <$> series+instance Monad m => CoSerial m Integer where+  coseries rs = (. (fromInteger :: Integer->Int)) <$> coseries rs -alts3 ::  (Serial a, Serial b, Serial c) =>-            Series d -> Series (a->b->c->d)-alts3 ds d = if d > 0 then coseries (coseries (coseries ds)) (dec d)-             else [\_ _ _ -> x | x <- ds d]+-- | 'N' is a wrapper for 'Integral' types that causes only non-negative values+-- to be generated. Generated functions of type @N a -> b@ do not distinguish+-- different negative values of @a@.+newtype N a = N a deriving (Eq, Ord, Real, Enum, Num, Integral) -alts4 ::  (Serial a, Serial b, Serial c, Serial d) =>-            Series e -> Series (a->b->c->d->e)-alts4 es d = if d > 0 then coseries (coseries (coseries (coseries es))) (dec d)-             else [\_ _ _ _ -> x | x <- es d]+instance (Integral a, Serial m a) => Serial m (N a) where+  series = generate $ \d -> map (N . fromIntegral) [0..d] -instance Serial Bool where-  series        = cons0 True \/ cons0 False-  coseries rs d = [ \x -> if x then r1 else r2-                  | r1 <- rs d, r2 <- rs d ]+instance (Integral a, Serial m a) => CoSerial m (N a) where+  coseries rs =+    alts0 rs >>- \z ->+    alts1 rs >>- \f ->+    return $ \(N i) ->+      if i > 0+        then f (N $ i-1)+        else z -instance Serial a => Serial (Maybe a) where-  series        = cons0 Nothing \/ cons1 Just-  coseries rs d = [ \m -> case m of-                       Nothing -> z-                       Just x  -> f x-                  |  z <- alts0 rs d ,-                     f <- alts1 rs d ]+instance Monad m => Serial m Float where+  series =+    series >>- \(sig, exp) ->+    guard (odd sig || sig==0 && exp==0) >>+    return (encodeFloat sig exp)+instance Monad m => CoSerial m Float where+  coseries rs =+    coseries rs >>- \f ->+      return $ f . decodeFloat -instance (Serial a, Serial b) => Serial (Either a b) where-  series        = cons1 Left \/ cons1 Right-  coseries rs d = [ \e -> case e of-                          Left x  -> f x-                          Right y -> g y-                  |  f <- alts1 rs d ,-                     g <- alts1 rs d ]+instance Monad m => Serial m Double where+  series = (realToFrac :: Float -> Double) <$> series+instance Monad m => CoSerial m Double where+  coseries rs =+    (. (realToFrac :: Double -> Float)) <$> coseries rs -instance Serial a => Serial [a] where-  series        = cons0 [] \/ cons2 (:)-  coseries rs d = [ \xs -> case xs of-                           []      -> y-                           (x:xs') -> f x xs'-                  |   y <- alts0 rs d ,-                      f <- alts2 rs d ]+instance Monad m => Serial m Char where+  series = generate $ \d -> take (d+1) ['a'..'z']+instance Monad m => CoSerial m Char where+  coseries rs =+    coseries rs >>- \f ->+    return $ \c -> f (N (fromEnum c - fromEnum 'a')) +instance (Monad m, Serial m a, Serial m b) => Serial m (a,b) where+  series = cons2 (,)+instance (Monad m, CoSerial m a, CoSerial m b) => CoSerial m (a,b) where+  coseries rs = uncurry <$> alts2 rs++instance (Monad m, Serial m a, Serial m b, Serial m c) => Serial m (a,b,c) where+  series = cons3 (,,)+instance (Monad m, CoSerial m a, CoSerial m b, CoSerial m c) => CoSerial m (a,b,c) where+  coseries rs = uncurry3 <$> alts3 rs++instance (Monad m, Serial m a, Serial m b, Serial m c, Serial m d) => Serial m (a,b,c,d) where+  series = cons4 (,,,)+instance (Monad m, CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d) => CoSerial m (a,b,c,d) where+  coseries rs = uncurry4 <$> alts4 rs++instance Monad m => Serial m Bool where+  series = cons0 True \/ cons0 False+instance Monad m => CoSerial m Bool where+  coseries rs =+    rs >>- \r1 ->+    rs >>- \r2 ->+    return $ \x -> if x then r1 else r2++instance (Monad m, Serial m a) => Serial m (Maybe a) where+  series = cons0 Nothing \/ cons1 Just+instance (Monad m, CoSerial m a) => CoSerial m (Maybe a) where+  coseries rs =+    maybe <$> alts0 rs <~> alts1 rs++instance (Monad m, Serial m a, Serial m b) => Serial m (Either a b) where+  series = cons1 Left \/ cons1 Right+instance (Monad m, CoSerial m a, CoSerial m b) => CoSerial m (Either a b) where+  coseries rs =+    either <$> alts1 rs <~> alts1 rs++instance Serial m a => Serial m [a] where+  series = cons0 [] \/ cons2 (:)+instance CoSerial m a => CoSerial m [a] where+  coseries rs =+    alts0 rs >>- \y ->+    alts2 rs >>- \f ->+    return $ \xs -> case xs of [] -> y; x:xs' -> f x xs'++instance (CoSerial m a, Serial m b, Monad m) => Serial m (a->b) where+  series = coseries series -- Thanks to Ralf Hinze for the definition of coseries -- using the nest auxiliary.-instance (Serial a, Serial b) => Serial (a->b) where-  series = coseries series-  coseries rs d =-    [ \ f -> g [ f a | a <- args ]-    | g <- nest args d ]-    where-    args = series d-    nest []     _ = [ \[] -> c-                    | c <- rs d ]-    nest (a:as) _ = [ \(b:bs) -> f b bs-                    | f <- coseries (nest as) d ]+instance (Serial m a, CoSerial m a, Serial m b, CoSerial m b, Monad m) => CoSerial m (a->b) where+  coseries r = do+    args <- unwind series --- | For customising the depth measure. Use with care!-depth :: Depth -> Depth -> Depth-depth d d' | d >= 0    = d'+1-d-           | otherwise = error "SmallCheck.depth: argument < 0"+    g <- nest r args+    return $ \f -> g $ map f args -dec :: Depth -> Depth-dec d | d > 0     = d-1-      | otherwise = error "SmallCheck.dec: argument <= 0"+    where -inc :: Depth -> Depth-inc d = d+1+    nest :: forall a b m c . (Serial m b, CoSerial m b) => Series m c -> [a] -> Series m ([b] -> c)+    nest rs args = do+      case args of+        [] -> const `liftM` rs+        _:rest -> do+          let sf = coseries $ nest rs rest+          f <- sf+          return $ \(b:bs) -> f b bs  -- show the extension of a function (in part, bounded both by -- the number and depth of arguments)-instance (Serial a, Show a, Show b) => Show (a->b) where+instance (Serial Identity a, Show a, Show b) => Show (a->b) where   show f =     if maxarheight == 1     && sumarwidth + length ars * length "->;" < widthLimit then@@ -439,7 +543,7 @@       concat $ [a++"->\n"++indent r | (a,r) <- ars]     where     ars = take lengthLimit [ (show x, show (f x))-                           | x <- series depthLimit ]+                           | x <- list depthLimit series ]     maxarheight = maximum  [ max (height a) (height r)                            | (a,r) <- ars ]     sumarwidth = sum       [ length a + length r@@ -447,3 +551,33 @@     indent = unlines . map ("  "++) . lines     height = length . lines     (widthLimit,lengthLimit,depthLimit) = (80,20,3)::(Int,Int,Depth)++-- }}}++------------------------------+-- Convenient wrappers+------------------------------+-- {{{++--------------------------------------------------------------------------+-- | @Positive x@: guarantees that @x \> 0@.+newtype Positive a = Positive { getPositive :: a }+ deriving (Eq, Ord, Num, Integral, Real, Enum)++instance (Num a, Ord a, Serial m a) => Serial m (Positive a) where+  series = Positive <$> series `suchThat` (> 0)++instance Show a => Show (Positive a) where+  showsPrec n (Positive x) = showsPrec n x++-- | @NonNegative x@: guarantees that @x \>= 0@.+newtype NonNegative a = NonNegative { getNonNegative :: a }+ deriving (Eq, Ord, Num, Integral, Real, Enum)++instance (Num a, Ord a, Serial m a) => Serial m (NonNegative a) where+  series = NonNegative <$> series `suchThat` (>= 0)++instance Show a => Show (NonNegative a) where+  showsPrec n (NonNegative x) = showsPrec n x++-- }}}
+ Test/SmallCheck/SeriesMonad.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Test.SmallCheck.SeriesMonad where++import Control.Applicative+import Control.Monad+import Control.Monad.Logic+import Control.Monad.Reader++-- | Maximum depth of generated test values.+--+-- For data values, it is the depth of nested constructor applications.+--+-- For functional values, it is both the depth of nested case analysis+-- and the depth of results.+type Depth = Int++-- | 'Series' is a `MonadLogic` action that enumerates values of a certain+-- type, up to some depth.+--+-- The depth bound is tracked in the 'SC' monad and can be extracted using+-- 'getDepth' and changed using 'localDepth'.+--+-- To manipulate series at the lowest level you can use its 'Monad',+-- 'MonadPlus' and 'MonadLogic' instances. This module provides some+-- higher-level combinators which simplify creating series.+--+-- A proper 'Series' should be monotonic with respect to the depth — i.e.+-- @localDepth (+1) s@ should emit all the values that @s@ emits (and+-- possibly some more).+--+-- It is also desirable that values of smaller depth come before the values+-- of greater depth.+newtype Series m a = Series (ReaderT Depth (LogicT m) a)+  deriving+    ( Functor+    , Monad+    , Applicative+    , MonadPlus+    , Alternative+    , MonadLogic)++instance MonadTrans Series where+  lift a = Series $ lift . lift $ a++runSeries :: Depth -> Series m a -> LogicT m a+runSeries d (Series a) = runReaderT a d
− examples/binarytries/BinaryTries.hs
@@ -1,79 +0,0 @@----------------------------------------------------- Binary tries representing sets of bitstrings.--- A test module for SmallCheck.--- Colin Runciman, May 2008.----------------------------------------------------module BinaryTries where--import Test.SmallCheck-import Test.SmallCheck.Series---- first representation--data BT1 = E | B Bool BT1 BT1 deriving Show--instance Serial BT1 where-  series = cons0 E \/ cons3 B---contains1 :: BT1 -> [Bool] -> Bool-contains1 E         _         = False-contains1 (B b _ _) []        = b-contains1 (B _ z _) (False:s) = contains1 z s-contains1 (B _ _ o) (True :s) = contains1 o s--prop_uniqueBT1 :: ([Bool]->Bool) -> Property-prop_uniqueBT1 f =-  exists1DeeperBy (+1) $ \bt -> contains1 bt === f---- second representation--data BT2  = E2 | NE BT2'-            deriving Show--data BT2' = T | O Bool BT2' | I Bool BT2' | OI Bool BT2' BT2'-            deriving Show--instance Serial BT2 where-  series = cons0 E2 \/ cons1 NE--instance Serial BT2' where-  series = cons0 T \/ cons2 O \/ cons2 I \/ cons3 OI--contains2 :: BT2 -> [Bool] -> Bool-contains2 = contains1 . convert--convert :: BT2 -> BT1-convert E2       = E-convert (NE bt') = convert' bt'--convert' :: BT2' -> BT1-convert' T            = B True E E-convert' (O  b    z') = B b (convert' z') E-convert' (I  b o'   ) = B b E (convert' o')-convert' (OI b o' z') = B b (convert' z') (convert' o')--prop_uniqueBT2 :: ([Bool]->Bool) -> Property-prop_uniqueBT2 f =-  exists1DeeperBy (+1) $ \bt -> contains2 bt === f--(===) :: Eq b => (a->b) -> (a->b) -> a -> Bool-f === g = \x -> f x == g x--main :: IO ()-main = do-  test1 "\\f -> exists1DeeperBy (+1) $ \\bt1 -> contains1 bt1 === f ?"-        prop_uniqueBT1-  test1 "\\f -> exists1DeeperBy (+1) $ \\bt1 -> contains2 bt2 === f ?"-        prop_uniqueBT2--test1 :: Testable a => String -> a -> IO ()-test1 s t = do-  rule-  putStrLn s-  rule-  smallCheck 2 t-  where-  rule = putStrLn "----------------------------------------------------------"-
− examples/binarytries/README
@@ -1,10 +0,0 @@-First see ../../README.--In this directory, BinaryTries.hs illustrates properties quantified-over functions and requiring the unique existence of a data-structure.-Two different trie representations are defined for sets of bitstrings.-The properties state that each set has a unique representation as a-trie -- true for the second representation, but not for the first.-The properties are specified using functions with boolean results-as a pure representation of sets, independent of any data structure.-Compile or interpret BinaryTries.main for the self-introducing tests.
− examples/circuits/BitAdd.hs
@@ -1,23 +0,0 @@-import Test.SmallCheck--and2 (a,b)       = a && b--xor2 (a,b)       = a /= b--halfAdd (a,b)    = (sum,carry)-  where sum      = xor2 (a,b)-        carry    = and2 (a,b)--bit False        = 0-bit True         = 1--num []           = 0-num (a:as)       = bit a + 2 * num as--bitAdd a []      = [a]-bitAdd a (b:bs)  = s : bitAdd c bs-  where (s,c)    = halfAdd (a,b)--prop_bitAdd a as = num (bitAdd a as) == bit a + num as--main             = smallCheck 8 prop_bitAdd
− examples/circuits/Mux.hs
@@ -1,114 +0,0 @@-import List-import Test.SmallCheck-import Test.SmallCheck.Series--type Bit             =  Bool--unaryMux             :: [Bit] -> [[Bit]] -> [Bit]-unaryMux sel xs      =  map (tree (||))-                     $  transpose-                     $  zipWith (\s x -> map (s &&) x) sel xs--tree                 :: (a -> a -> a) -> [a] -> a-tree f [x]           =  x-tree f (x:y:ys)      =  tree f (ys ++ [f x y])--decode               :: [Bit] -> [Bit]-decode []            =  [True]-decode [x]           =  [not x,x]-decode (x:xs)        =  concatMap (\y -> [not x && y,x && y]) rest-  where-    rest             =  decode xs--binaryMux            :: [Bit] -> [[Bit]] -> [Bit]-binaryMux sel xs     =  unaryMux (decode sel) xs--bitMux2              :: Bit -> Bit -> Bit -> Bit-bitMux2 sel x y      =  (sel && y) || (not sel && x)--muxf5                =  bitMux2--muxf6                =  bitMux2--busMux2              :: Bit -> [Bit] -> [Bit] -> [Bit]-busMux2 sel xs ys    =  zipWith (bitMux2 sel) xs ys--bitMux8              :: [Bit] -> [Bit] -> Bit-bitMux8 _ [x]        =  x-bitMux8 (s0:_) [x0,x1]-                     =  bitMux2 s0 x0 x1-bitMux8 (s0:s1:_) [x0,x1,x2,x3]-                     =  muxf5 s1 (bitMux8 [s0] [x0,x1]) (bitMux8 [s0] [x2,x3])-bitMux8 (s0:s1:s2:_) [x0,x1,x2,x3,x4,x5,x6,x7]-                     =  muxf6 s2 (bitMux8 [s0,s1] [x0,x1,x2,x3])-                                 (bitMux8 [s0,s1] [x4,x5,x6,x7])-bitMux8 sels xs      =  bitMux8 (take n sels) (pad m xs)-  where-    n                =  log2 (length xs)-    m                =  2 ^ n--log2                 :: Int -> Int-log2 n               =  length (takeWhile (< n) (iterate (*2) 1))--pad                  :: Int -> [Bit] -> [Bit]-pad n xs | m > n     =  xs-         | otherwise =  xs ++ replicate (n-m) False-  where-    m                =  length xs--bitMux               :: [Bit] -> [Bit] -> Bit-bitMux sels [x]      =  x-bitMux sels xs       =  bitMux (drop 3 sels) ys-  where-    ys               =  zipWith bitMux8 (repeat (take 3 sels)) (groupn 8 xs)---groupn               :: Int -> [a] -> [[a]]-groupn n []          =  []-groupn n xs          =  take n xs : groupn n (drop n xs)--binaryMux'           :: [Bit] -> [[Bit]] -> [Bit]-binaryMux' sel       =  map (bitMux sel) . transpose--num                  :: [Bit] -> Int-num []               =  0-num (a:as)           =  fromEnum a + 2 * num as---- Property 0: binaryMux is correct--prop_mux0 sel xs     =  length xs == 2 ^ length sel-                     && all ((== length (head xs)) . length) xs-                    ==> binaryMux sel xs == xs !! num sel---- But this is inefficient as most of the test cases do not meet the--- antecedent.  Instead, we can define a custom generator in which--- the number of inputs grows exponentially (i.e. 2^) with respect to--- the width of the address word.--newtype Word         =  Word { bits :: [Bit] }-                          deriving Show--newtype File         =  File { wrds :: [Word] }-                          deriving Show--instance Serial Word where-  series n  = map Word $ sequence (replicate n [False,True])--instance Serial File where-  series n  = map File $ sequence $ replicate (2^n) ws-    where-      ws    = series n :: [Word]--prop_mux0' sel xs    =  xs' !! num sel' == binaryMux sel' xs'-  where-    sel'             =  bits sel-    xs'              =  map bits (wrds xs)---- Property 1: binaryMux' is correct--prop_mux1 sel xs     =  xs' !! num sel' == binaryMux' sel' xs'-  where-    sel'             =  bits sel-    xs'              =  map bits (wrds xs)--main                 =  smallCheck 2 prop_mux1
− examples/circuits/README
@@ -1,30 +0,0 @@-First see ../../README.--The programs in this directory define a number of different circuits.-Some of these were originally written in Lava and were used to generate-circuit netlists for external synthesis tools and propositional logic for-external theorem provers.  They have been slightly adapted as examples-for SmallCheck, so that they do not depend on Lava.--BitAdd.hs defines a trivial circuit that takes two inputs, a bit and a-bit-vector (i.e. a list of bits), and returns a bit-vector containing-the sum of the two.  Using SmallCheck, it is straightforward to verify-that the circuit behaves correctly for all bit-vector inputs up to the-given size.--Sad.hs defines a more complicated circuit that works over two lists of-lists of bits, but verification with SmallCheck is just as simple and-useful as before.--Mux.hs defines a simple multiplexor and a more complicated variant that-is optimised for Xilinx FPGAs.  Originally, the correctness of the more-complicated version was argued by verifying its equivalence with the-simpler version using an external SAT solver.  However, using SmallCheck,-more general properties can be expressed, and so each circuit can be-verified independently in terms of Haskell's list indexing operator (!!).-The correctness properties are again easy to express in SmallCheck,-but their antecedents filter out so many test cases as to make them-inefficient.  This problem is resolved by writing a custom test-case-generator using SmallCheck's "Serial" class.--Matthew Naylor, University of York, 22nd Jan 2007.
− examples/circuits/Sad.hs
@@ -1,96 +0,0 @@-import Test.SmallCheck---- We take the following specification for the sum of absolute--- differences, and develop a circuit generator that has the same--- behaviour.--sad                            ::  [Int] -> [Int] -> Int-sad xs ys                      =   sum (map abs (zipWith (-) xs ys))--type Bit                       =   Bool--low                            ::  Bit-low                            =   False--high                           ::  Bit-high                           =   True--inv                            ::  Bit -> Bit-inv a                          =   not a--and2                           ::  Bit -> Bit -> Bit-and2 a b                       =   a && b-or2 a b                        =   a || b-xor2 a b                       =   a /= b-xnor2 a b                      =   a == b--mux2                           ::  Bit -> Bit -> Bit -> Bit-mux2 sel a b                   =   (sel && b) || (not sel && a)--bitAdd                         ::  Bit -> [Bit] -> [Bit]-bitAdd x []                    =   [x]-bitAdd x (y:ys)                =   let  (sum,carry) = halfAdd x y-                                   in   sum:bitAdd carry ys--halfAdd x y                    =   (xor2 x y,and2 x y)--binAdd                         ::  [Bit] -> [Bit] -> [Bit]-binAdd xs ys                   =   binAdd' low xs ys--binAdd' cin   []       []      =   [cin]-binAdd' cin   (x:xs)   []      =   bitAdd cin (x:xs)-binAdd' cin   []       (y:ys)  =   bitAdd cin (y:ys)-binAdd' cin   (x:xs)   (y:ys)  =   let  (sum,cout) = fullAdd cin x y-                                   in   sum:binAdd' cout xs ys--fullAdd cin a b                =   let  (s0,c0)  =  halfAdd a b-                                        (s1,c1)  =  halfAdd cin s0-                                   in   (s1,xor2 c0 c1)--binGte                         ::  [Bit] -> [Bit] -> Bit-binGte xs ys                   =   binGte' high xs ys--binGte' gin  []      []        =   gin-binGte' gin  (x:xs)  []        =   orl (gin:x:xs)-binGte' gin  []      (y:ys)    =   and2 gin (orl (y:ys))-binGte' gin  (x:xs)  (y:ys)    =   let  gout = gteCell gin x y-                                   in   binGte' gout xs ys--gteCell gin x y                =   mux2 (xnor2 x y) x gin--orl                            ::  [Bit] -> Bit-orl xs                         =   tree or2 low xs--binDiff                        ::  [Bit] -> [Bit] -> [Bit]-binDiff xs ys                  =   let  xs'   =  pad (length ys) xs-                                        ys'   =  pad (length xs) ys-                                        gte   =  binGte xs' ys'-                                        xs''  =  map (xor2 (inv gte)) xs'-                                        ys''  =  map (xor2 gte) ys'-                                   in   init (binAdd' high xs'' ys'')-  -pad                            ::  Int -> [Bit] -> [Bit]-pad n xs | m > n               =   xs-         | otherwise           =   xs ++ replicate (n-m) False-  where-    m                          =   length xs--tree                           ::  (a -> a -> a) -> a -> [a] -> a-tree f z []                    =   z-tree f z [x]                   =   x-tree f z (x:y:ys)              =   tree f z (ys ++ [f x y])--binSum                         ::  [[Bit]] -> [Bit]-binSum xs                      =   tree binAdd [] xs--binSad                         ::  [[Bit]] -> [[Bit]] -> [Bit]-binSad xs ys                   =   binSum (zipWith binDiff xs ys)--num                            ::  [Bit] -> Int-num []                         =   0-num (a:as)                     =   fromEnum a + 2 * num as--prop_binSad xs ys              =   sad (map num xs) (map num ys)-                                     == num (binSad xs ys)--main                           =   smallCheck 3 prop_binSad
− examples/imperative/Behaviour.hs
@@ -1,23 +0,0 @@-module Behaviour(Trace(..),(+++),approx) where--data Trace a-  = Step (Trace a)-  | a :> Trace a-  | End-  | Crash-  deriving (Eq, Show)--(+++) :: Trace a -> Trace a -> Trace a-Step s   +++ t = Step (s +++ t)-(x :> s) +++ t = x :> (s +++ t)-End      +++ t = t-Crash    +++ t = Crash--approx :: Eq a => Int -> Trace a -> Trace a -> Bool-approx 0 _        _        = True-approx n (a :> s) (b :> t) = a == b && approx (n-1) s t-approx n (Step s) (Step t) = approx (n-1) s t-approx n End    End        = True-approx n Crash  Crash      = True-approx n _        _        = False-
− examples/imperative/Compiler.hs
@@ -1,59 +0,0 @@-module Compiler(compile) where--import Machine-import Syntax-import StackMap-import Value--compile :: Command -> [Instruction]-compile c =-  replicate (depth sm) (Push Wrong) ++-  compObey sm c ++-  [Halt]-  where-  sm = stackMap c--compObey :: StackMap -> Command -> [Instruction]-compObey sm Skip = -  []-compObey sm (v := e) =-  compEval sm e ++-  [Store (location sm v + 1)]-compObey sm (c1 :-> c2) =-  compObey sm c1 ++-  compObey sm c2-compObey sm (If e c1 c2) =-  compEval sm e ++-  [JumpUnless (length isc1 + 1)] ++-  isc1 ++-  [Jump (length isc2)] ++-  isc2-  where-  isc1 = compObey sm c1-  isc2 = compObey sm c2-compObey sm (While e c) =-  ise ++-  [JumpUnless (length isc + 1)] ++-  isc ++-  [Jump (negate (length isc + 1 + length ise + 1))]-  where-  ise = compEval sm e-  isc = compObey sm c-compObey sm (Print e) =-  compEval sm e ++-  [Display]--compEval :: StackMap -> Expr -> [Instruction]-compEval sm (Val v) =-  [Push v]-compEval sm (Var v) =-  [Fetch (location sm v)]-compEval sm (Uno op1 e) =-  -- was op before arg eval  -  compEval sm e ++-  [Instr1 op1]-compEval sm (Duo op2 e1 e2) =-  -- was op before arg evals  -  compEval sm        e1 ++-  compEval (push sm) e2 ++-  [Instr2 op2]
− examples/imperative/Interpreter.hs
@@ -1,41 +0,0 @@-module Interpreter(obey) where--import Syntax-import Behaviour-import Value--type Env = [(Name,Value)]--obey :: Command -> Trace Value-obey p = fst (run p [])--look :: Name -> Env -> Value-look x s = maybe Wrong id (lookup x s)--update :: Name -> Value -> Env -> Env-update x a s = (x,a) : filter (\(y,_) -> y/=x) s--run :: Command -> Env -> (Trace Value, Env)-run Skip        s = (End, s)-run (x := e)    s = (End, update x (eval e s) s)-run (p :-> q)   s = let (outp, sp) = run p s-                        (outq, sq) = run q sp-                    in (outp +++ outq, sq)-run (If e p q)  s = case eval e s of-                    -- was True -> q, False -> p-                    Log True  -> run p s-                    Log False -> run q s-                    _         -> (Crash, s)-run (While e p) s = case eval e s of-                    Log True  -> let (outp,sp) = run p s-                                     (outw,sw) = run (While e p) sp-                                 in (outp +++ Step outw, sw)-                    Log False -> (End, s)-                    _         -> (Crash, s)-run (Print e)   s = (eval e s :> End, s)--eval :: Expr -> Env -> Value-eval (Var x)      s = look x s-eval (Val v)      s = v-eval (Uno op a)   s = uno op (eval a s)-eval (Duo op a b) s = duo op (eval a s) (eval b s)
− examples/imperative/Machine.hs
@@ -1,50 +0,0 @@-module Machine(Instruction(..), exec) where--import Array-import Behaviour-import Value--data Instruction-  = Push Value-  | Pop-  | Fetch Int-  | Store Int-  | Instr1 Op1-  | Instr2 Op2-  | Display-  | Jump Int-  | JumpUnless Int-  | Halt- deriving (Eq, Show)- -exec :: [Instruction] -> Trace Value-exec instrs = run 1 []-  where-  size   = length instrs-  memory = array (1,size) ([1..] `zip` instrs)-  run pc stack =-    if pc < 1 || size < pc then Crash-    else-      case (memory ! pc, stack) of-      (Push x	    , stack)          -> run pc' (x : stack)-      (Pop	    , _ : stack)      -> run pc' stack-      (Fetch n      , stack)	 -        | length stack >  n           -> run pc' (stack !! n : stack)-      (Store n      , x : stack)-        | length stack >= n           -> run pc' (take (n-1) stack ++-                                                  x : drop n stack)-      (Instr1 op1   , i : stack)      -> run pc' (uno op1 i : stack)-      (Instr2 op2   , i : j : stack)  -> run pc' (duo op2 j i : stack)-      (Display      , i : stack)      -> i :> run pc' stack-      (Jump n	    , stack)	      -> step n (run (pc' + n) stack)-      (JumpUnless n , Log b : stack)-        | b	                      -> run pc' stack-        | otherwise                   -> step n (run (pc' + n) stack)-      (Halt	    , stack)	      -> End-      _ 			      -> Crash-     where-      pc' = pc + 1--step :: Int -> Trace Value -> Trace Value    -step n t | n < 0     = Step t-         | otherwise = t
− examples/imperative/Properties.hs
@@ -1,178 +0,0 @@-import Behaviour-import Interpreter-import Compiler-import Machine-import Syntax-import Value--import Test.SmallCheck--------------- <series of expressions and commands> ----------------- In the abstract syntax variables are just strings,--- but we do not want to enumerate all lists of characters.--- Just a couple of distinct names.--newtype VarName = VarName Name--instance Serial VarName where-  series = const [VarName [c] | c <- ['a'..'b']]--var :: VarName -> Expr-var (VarName v) = Var v--assign :: VarName -> Expr -> Command-assign (VarName v) e = (v := e)---- Uses of depth 0 ensure that all occurrences of variables--- or literals are treated as zero-depth atoms.--- The rest is completely standard, but for the use of--- 'var' for Var and 'assign' for Assign.--instance Serial Value where-  series = cons0 Wrong-        \/ cons1 Log . depth 0-        \/ cons1 Num . depth 0--instance Serial Op1 where-  series = const [Not, Minus]--instance Serial Op2 where-  series = const [And, Or, Eq, Less, LessEq,-                  Add, Sub, Mul, Div, Mod]--instance Serial Expr where-  series = cons1 var . depth 0-        \/ cons1 Val . depth 0-        \/ cons2 Uno-        \/ cons3 Duo--instance Serial Command where-  series = cons0 Skip-        \/ cons1 Print-        \/ cons2 assign-        \/ cons2 (:->)-        \/ cons3 If-        \/ cons2 While------------------- <Closed Expressions> ----------------------- If we want a series for a subset of the values in--- a given type, one way to define it is via a newtype.--- Here, expressions without variables.--newtype ClosedExpr = Closed Expr deriving Show--instance Serial ClosedExpr where-  series = cons1 val . depth 0-        \/ cons2 uno-        \/ cons3 duo-    where-    val v = Closed (Val v)-    uno op (Closed e) = Closed (Uno op e)-    duo op (Closed e1) (Closed e2) = Closed (Duo op e1 e2)------------------- <Customised Programs> --------------------- The space of all commands grows very quickly with depth,--- and many syntactically legal commands are bound to fail.--- Here we define a restricted subset of commands in a--- 'standard form':--- -- Skip only occurs as an else-alternative--- -- Print is only applied to simple variables--- -- Only integer values are assigned to variables.--- -- If and While conditions are compound comparisons.--newtype StdCommand = Std Command deriving Show--instance Serial StdCommand where-  series = cons1 print'-        \/ cons2 assign'-        \/ cons2 seq'-        \/ cons3 if'-        \/ cons2 while'-    where-    print'  (VarName v)                   = Std (Print (Var v))-    assign' (VarName v) (I e)             = Std (v := e)-    seq'    (Std c0) (Std c1)             = Std (c0 :-> c1)-    if'     (B e) (Std c0) (SkipOrStd c1) = Std (If e c0 c1)-    while'  (B e) (Std c)                 = Std (While e c)--newtype SkipOrStdCommand = SkipOrStd Command--instance Serial SkipOrStdCommand where-  series = cons0 skip-        \/ cons1 std . depth 0-    where-    skip        = SkipOrStd Skip-    std (Std c) = SkipOrStd c--newtype IExpr = I Expr--instance Serial IExpr where-  series = cons1 var' . depth 0-        \/ cons1 val' . depth 0-        \/ cons1 uno'-        \/ cons3 duo'-    where-    var' (VarName v)          = I (Var v)-    val' i                    = I (Val (Num i))-    uno' (I e)                = I (Uno Minus e)-    duo' (I2 d) (I e0) (I e1) = I (Duo d e0 e1)--newtype IOp2 = I2 Op2--instance Serial IOp2 where-  series = const [I2 op | op <- [Add, Sub, Mul, Div, Mod]]--newtype BExpr = B Expr- -instance Serial BExpr where-  series = cons1 uno'-        \/ cons3 duo'-        \/ cons3 cmp'-    where-    uno' (B e)                = B (Uno Not e)-    duo' (B2 d) (B e0) (B e1) = B (Duo d e0 e1)-    cmp' (C2 c) (I e0) (I e1) = B (Duo c e0 e1)--newtype BOp2 = B2 Op2--instance Serial BOp2 where-  series = const [B2 op | op <- [And,Or]]--newtype COp2 = C2 Op2--instance Serial COp2 where-  series = const [C2 op | op <- [Eq,Less,LessEq]]---------- <depth-bounded equivalence of program traces> ----------newtype Approx = Approx Int deriving Show--instance Serial Approx where-  series d = [Approx d]--(=~=) :: Eq a => Trace a -> Trace a -> Approx -> Bool-s =~= t = \(Approx d) -> approx d s t------------------- <congruence properties> --------------------prop_Congruence :: Command -> Property-prop_Congruence p =-  t1 /= Crash || t2 /= Crash ==>-    (t1 =~= t2)-  where-  t1 = obey p-  t2 = exec (compile p)--prop_StdCongruence :: StdCommand -> Property-prop_StdCongruence (Std p) =-  prop_Congruence p--main :: IO ()-main = do-  putStrLn "-- congruence for all programs:"-  smallCheck 2 prop_Congruence-  putStrLn "-- congruence for standard-form programs:"-  smallCheck 2 prop_StdCongruence
− examples/imperative/README
@@ -1,10 +0,0 @@-First see ../../README.--This directory gives the largest illustrative example.  We test for-congruence between an interpreter and compiler for a small imperative-language.  The example is adapted from an original using QuickCheck,-as described in the lecture notes for AFP'02 (LNCS 2638).  Compared-with the simpler example in ../logic, here specialised instances-are used to restrict the input space to programs in a standard form.-Run Properties.main and compare the rate of growth for the last two-properties tested.
− examples/imperative/StackMap.hs
@@ -1,35 +0,0 @@-module StackMap where--import Syntax-import List( union )--type StackMap = (Int,[Name])--stackMap :: Command -> StackMap-stackMap c = (0, comVars c)--push :: StackMap -> StackMap-push (n, vars) = (n+1, vars)--pop :: StackMap -> StackMap-pop (n, vars) = (n-1, vars)--location :: StackMap -> Name -> Int-location (n, vars) v = n + length (takeWhile (/=v) vars)--depth :: StackMap -> Int-depth (n, vars) = n + length vars--expVars :: Expr -> [Name]-expVars (Var v)     = [v]-expVars (Val _)     = []-expVars (Uno _ a)   = expVars a-expVars (Duo _ a b) = expVars a `union` expVars b--comVars :: Command -> [Name]-comVars Skip         = []-comVars (x := e)     = [x] `union` expVars e-comVars (c1 :-> c2)  = comVars c1 `union` comVars c2-comVars (If e c1 c2) = expVars e `union` comVars c1 `union` comVars c2-comVars (While e c)  = expVars e `union` comVars c-comVars (Print e)    = expVars e
− examples/imperative/Syntax.hs
@@ -1,21 +0,0 @@-module Syntax(Name, Expr(..), Command(..)) where--import Value--type Name = String--data Expr-  = Var Name-  | Val Value-  | Uno Op1 Expr-  | Duo Op2 Expr Expr-  deriving (Eq, Show)--data Command-  = Skip-  | Name := Expr-  | Command :-> Command-  | If Expr Command Command-  | While Expr Command-  | Print Expr-  deriving (Eq, Show)
− examples/imperative/Value.hs
@@ -1,44 +0,0 @@-module Value(Value(..), Op1(..), Op2(..), uno, duo) where--data Value-  = Num Int-  | Log Bool-  | Wrong-  deriving (Eq, Show)--data Op1-  = Not-  | Minus-  deriving (Eq, Show)--data Op2-  = And-  | Or-  | Mul-  | Add-  | Sub-  | Div-  | Mod-  | Less-  | LessEq -  | Eq-  deriving (Eq, Show)--uno :: Op1 -> Value -> Value-uno Not   (Log b) = Log (not b)-uno Minus (Num n) = Num (negate n)-uno _     _       = Wrong--duo :: Op2 -> Value -> Value -> Value-duo And     (Log a) (Log b)          = Log (a && b)-duo Or      (Log a) (Log b)          = Log (a || b)-duo Eq      (Log a) (Log b)          = Log (a == b)-duo Mul     (Num m) (Num n)          = Num (m * n)-duo Add     (Num m) (Num n)          = Num (m + n)-duo Sub     (Num m) (Num n)          = Num (m - n)-duo Div     (Num m) (Num n) | n /= 0 = Num (m `div` n)-duo Mod     (Num m) (Num n) | n /= 0 = Num (m `mod` n)-duo Less    (Num m) (Num n)          = Log (m < n)-duo LessEq  (Num m) (Num n)          = Log (m <= n)-duo Eq      (Num m) (Num n)          = Log (m == n)-duo _       _       _                = Wrong
− examples/listy/ListProps.hs
@@ -1,92 +0,0 @@---------------------------------------------------- Properties (some valid some invalid) of a few--- standard list-processing functions.--- A test module for SmallCheck.--- Colin Runciman, August 2006.--- Revised for 0.2, November 2006.---------------------------------------------------module ListProps where--import Test.SmallCheck---- properties about higher-order functions--- plausible-looking but invalid laws about folds--prop_fold1 :: [Bool] -> Property-prop_fold1 xs =-  not (null xs) ==>-    \f -> foldl1 f xs == foldr1 f xs--prop_fold2 :: [Bool] -> [Bool] -> Property-prop_fold2 xs ys =-  not (null xs) && not (null ys) ==>-    \f -> foldr1 f xs `f` foldr1 f ys == foldr1 f (xs++ys)---- properties using 'exists' with data and functional arguments---- invalid because depth-bound for zs same as for xs ys-prop_union1 :: [Bool] -> [Bool] -> Property-prop_union1 xs ys =-  exists $ \zs ->-    \b -> (b `elem` zs) == (b `elem` xs || b `elem` ys)---- valid variant: depth-bound doubled in existential-prop_union2 :: [Bool] -> [Bool] -> Property-prop_union2 xs ys =-  existsDeeperBy (*2) $ \zs ->-    \b -> (b `elem` zs) == (b `elem` xs || b `elem` ys)---- do magical span arguments exist?-prop_span1 :: [Bool] -> [Bool] -> [Bool] -> Property-prop_span1 xs ys zs =-  xs++ys == zs ==> exists $ \t -> (xs,ys) == span t zs---- deliberate mistake in final isPrefix equation-isPrefix :: Ord a => [a] -> [a] -> Bool-isPrefix [] ys = True-isPrefix (x:xs) [] = False-isPrefix (x:xs) (y:ys) = x==y || isPrefix xs ys---- this completeness property still holds-isPrefixComplete :: String -> String -> Bool-isPrefixComplete xs ys =-  isPrefix xs (xs ++ ys)---- but this existential soundness property fails-isPrefixSound :: String -> String -> Property-isPrefixSound xs ys = isPrefix xs ys ==>-  exists $ \xs' -> ys == (xs ++ xs')--main :: IO ()-main = do-  test1 "\\xs -> not (null xs) ==>\n\-        \  \\f -> foldl1 f xs == foldr1 f xs ?"-        prop_fold1-  test1 "\\xs ys -> not (null xs) && not (null ys) ==>\n \-        \  \\f -> foldr1 f xs `f` foldr1 f ys == foldr1 f (xs++ys) ?"-        prop_fold2-  test1 "\\xs ys -> exists $ \\zs ->\n\-        \  \\b -> (b `elem` zs) == (b `elem` xs || b `elem` ys) ?"-        prop_union1-  test1 "\\xs ys -> existsDeeperBy (*2) $ \\zs ->\n\-        \  \\b -> (b `elem` zs) == (b `elem` xs || b `elem` ys) ?"-        prop_union2-  test1 "\\xs ys zs -> xs++ys==zs ==>\n\-        \  exists $ \\t -> (xs,ys) == span t zs ?"-        prop_span1-  test1 "\\xs ys -> isPrefix xs (xs++ys) ?"-        isPrefixComplete-  test1 "\\xs ys zs -> isPrefix xs ys ==>\n\-        \  exists $ \\xs' -> ys == xs ++ xs' ?"-        isPrefixSound--test1 :: Testable a => String -> a -> IO ()-test1 s t = do-  rule-  putStrLn s-  rule-  smallCheck 4 t-  where-  rule = putStrLn "----------------------------------------------------"-
− examples/listy/README
@@ -1,8 +0,0 @@-First see ../../README.--In this directory, compile or interpret ListProps.main (SmallCheck is-the only other module required) for a small selection of self-introducing-tests of list-processing functions.--The definition of isPrefix is deliberately incorrect: the completeness-property still holds, but the existential soundness property fails.
− examples/logical/LogicProps.hs
@@ -1,129 +0,0 @@-------------------------------------------------------- Propositional formulae, satisfiable, tautologous.--- A test module for SmallCheck.--- Colin Runciman, August 2006.-------------------------------------------------------module PropLogic where--import Test.SmallCheck-import Test.SmallCheck.Series--import List (nub)--data Prop = Var Name-          | Not Prop-          | And Prop Prop-          | Or  Prop Prop-          | Imp Prop Prop--instance Show Prop where-  show p = case p of-           Var n   -> show n-           Not q   -> "~"++show' q-           And q r -> show' q++"&"++show' r-           Or  q r -> show' q++"|"++show' r-           Imp q r -> show' q++"=>"++show' r-    where-    show' x = if priority p > priority x then "("++show x++")"-              else show x-    priority (Var _)   = 5-    priority (Not _)   = 4-    priority (And _ _) = 3-    priority (Or  _ _) = 2-    priority (Imp _ _) = 1--data Name = P | Q | R deriving (Eq,Show)--type Env = Name -> Bool--eval :: Prop -> Env -> Bool-eval (Var v)   env = env v-eval (Not p)   env = not (eval p env)-eval (And p q) env = eval p env && eval q env-eval (Or  p q) env = eval p env || eval q env-eval (Imp p q) env = eval p env <= eval q env --envsFor :: Prop -> [Env]-envsFor p = foldr bind [const False] (nub (varsOf p))-  where-  bind v es = concat [ [\x -> x==v || e x, e]-                     | e <- es ]--varsOf :: Prop -> [Name]-varsOf (Var v)   = [v]-varsOf (Not p)   = varsOf p-varsOf (And p q) = varsOf p ++ varsOf q-varsOf (Or  p q) = varsOf p ++ varsOf q-varsOf (Imp p q) = varsOf p ++ varsOf q--tautologous :: Prop -> Bool-tautologous p = all (eval p) (envsFor p)--satisfiable :: Prop -> Bool-satisfiable p = any (eval p) (envsFor p)--instance Serial Name where -  series        = cons0 P \/ cons0 Q \/ cons0 R -  coseries rs d = [ \n -> case n of-                          P -> x ; Q -> y ; R -> z               -                  |  x <- alts0 rs d, y <- alts0 rs d, z <- alts0 rs d ]--instance Serial Prop where-  series = cons1 Var-        \/ cons1 Not-        \/ cons2 And-        \/ cons2 Or-        \/ cons2 Imp------------------------ <properties for testing> -----------------------prop_taut1 :: Prop -> Property-prop_taut1 p =-  tautologous p ==> \e -> eval p e--prop_taut2 :: Prop -> Property-prop_taut2 p =-  not (tautologous p) ==> exists (\e -> not $ eval p e)--prop_sat1 :: Prop -> Env -> Property-prop_sat1 p e = -  eval p e ==> satisfiable p--prop_sat2 :: Prop -> Property-prop_sat2 p =-  satisfiable p ==> exists (\e -> eval p e)--prop_tautSat1 :: Prop -> Property-prop_tautSat1 p =-  not (tautologous p) ==> satisfiable (Not p)--prop_tautSat2 :: Prop -> Property-prop_tautSat2 p =-  not (satisfiable p) ==> tautologous (Not p)--main :: IO ()-main = do-  test1 "\\p -> tautologous p ==> \\e -> eval p e ?"-        prop_taut1-  test1 "\\p -> not (tautologous p) ==>\n\-        \  exists (\\e -> not $ eval p e) ?"-        prop_taut2-  test1 "\\p e -> eval p e ==> satisfiable p ?"-        prop_sat1-  test1 "\\p -> satisfiable p ==> exists (\\e -> eval p e) ?"-        prop_sat2-  test1 "\\p -> not (tautologous p) ==> satisfiable (Not p) ?"-        prop_tautSat1-  test1 "\\p -> not (satisfiable p) ==> tautologous (Not p) ?"-        prop_tautSat2--test1 :: Testable a => String -> a -> IO ()-test1 s t = do-  rule-  putStrLn s-  rule-  smallCheck 3 t-  where-  rule = putStrLn "----------------------------------------------------"-
− examples/logical/README
@@ -1,7 +0,0 @@-First see ../../README.--In this directory, LogicProps.hs illustrates the basic way to define-Serial instances of your own types, and hence Testable properties of-functions over them. Compile or interpret LogicProps.main (SmallCheck is-the only other module required) for a small selection of self-introducing-tests.
− examples/numeric/NumProps.hs
@@ -1,64 +0,0 @@-------------------------------------------- Illustrating numerics in SmallCheck--- Colin Runciman, November 2006.--- Modified for SmallCheck 0.3, May 2008-------------------------------------------import Test.SmallCheck-import Test.SmallCheck.Series-import Test.SmallCheck.Property--primes :: [Int]-primes = sieve [2..]-  where-  sieve (p:xs) =-    p : filter (noFactorIn primes) xs-  noFactorIn (p:ps) x =-    p*p > x || x `mod` p > 0 && noFactorIn ps x---- using natural numbers--prop_primes1 :: Nat -> Property-prop_primes1 (N n) =-  n > 1 ==> forAll (`take` primes) $ \p ->-    p `mod` n > 0 || n == p--prop_primes2 :: Nat -> Property-prop_primes2 (N n) =-  n > 0 ==> exists1 $ \exponents ->-    (null exponents || last exponents /= N 0) && -    n == product (zipWith power primes exponents)-  where-  power p (N e) = product (replicate e p)---- using floating point numbers--prop_logExp :: Float -> Bool-prop_logExp x = exp (log x) == x--prop_recipRecip :: Float -> Bool-prop_recipRecip x = 1.0 / (1.0 / x) == x--main :: IO ()-main = do-  test1 "\\(N n) -> n > 1 ==> forAll (`take` primes) $ \\p ->\n\-        \  p `mod` n > 0 || n == p"-        prop_primes1-  test1 "\\(N n) -> n > 0 ==> exists1 $ \\exponents ->\n\-        \  (null exponents || last exponents /= N 0) &&\n\-        \  n == product (zipWith power primes exponents)"-        prop_primes2-  test1 "\\x -> exp (log x) == x"-        prop_logExp-  test1 "\\x -> 1.0 / (1.0 / x) == x"-        prop_recipRecip--test1 :: Testable a => String -> a -> IO ()-test1 s t = do-  rule-  putStrLn s-  rule-  smallCheck 8 t-  where-  rule = putStrLn "----------------------------------------------------"-
− examples/numeric/README
@@ -1,14 +0,0 @@-First see ../../README.--In this directory, NumProps.hs illustrates the use of test series-for natural numbers, either by explicit signatures including Nat (or-Natural) or by use of the N constructor.  It also illustrates use of-floating-point series. Compile or interpret NumProps (SmallCheck is-the only other module required) and run main for a small selection of-self-introducing tests -- a couple about natural numbers and primes,-and a couple about floating point numbers.--For version 0.3 the second property about primes has been strengthened-by making the existence unique.  The restriction on the exponent list-was prompted by reports of non-uniqueness when the 'exists1' version-was first tested.
− examples/regular/README
@@ -1,8 +0,0 @@-First see ../../README.--In this directory, Regular.hs illustrates a test involving IO -- writing-and reading expressions to/from a file.  The use of 'smart constructors'-in the series definition is necessary for the property to hold, but does-*not* reduce the number of tests -- rather, there are duplicated tests for-the same expressions generated in different ways. Compile or interpret-Regular.main for a self-introducing test.
− examples/regular/Regular.hs
@@ -1,104 +0,0 @@-module Regular where--import Char (isAlpha)-import List (intersperse)-import Monad (liftM)--import Test.SmallCheck-import Test.SmallCheck.Series---- A data type of regular expressions.--data RE = Emp-        | Lam-        | Sym Char-        | Alt [RE]-        | Cat [RE]-        | Rep RE-        deriving Eq--isEmp, isLam, isSym, isCat, isAlt, isRep :: RE -> Bool-isEmp Emp     = True-isEmp _       = False-isLam Lam     = True-isLam _       = False-isSym (Sym _) = True-isSym _       = False-isAlt (Alt _) = True-isAlt _       = False-isCat (Cat _) = True-isCat _       = False-isRep (Rep _) = True-isRep _       = False---- Syms may be used to represent terminals or variables.--- Using cat and alt instead of Cat and Alt ensures that:--- (1) Cat and Alt arguments are multi-item lists;--- (2) items in Cat arguments are not Cats;--- (3) items in Alt arguments are not Alts.--cat :: [RE] -> RE-cat []  = Lam-cat [x] = x-cat xs  = Cat (concatMap catList xs)-  where-  catList (Cat ys) = ys-  catList z        = [z]--alt :: [RE] -> RE-alt []  = Emp-alt [x] = x-alt xs  = Alt (concatMap altList xs)-  where-  altList (Alt ys) = ys-  altList z        = [z]--instance Read RE where-  readsPrec _ s  = [rest s [[[]]]]--rest :: String -> [[[RE]]] -> (RE,String)-rest ""      (    a:as) = if null as then (a2re a,"")-                          else wrong-rest ('+':s) ((c:a):as) = if null c then wrong-			  else rest s (([]:c:a):as)-rest ('*':s) ((c:a):as) = case c of-                          []     -> wrong-                          (x:xs) -> rest s (((Rep x:xs):a):as)-rest ('0':s) ((c:a):as) = rest s (((Emp:c):a):as)-rest ('1':s) ((c:a):as) = rest s (((Lam:c):a):as)-rest ('(':s) as         = rest s ([[]]:as)-rest (')':s) (a:as)     = case as of-                          [] -> wrong-			  ((c:a'):as') -> rest s (((a2re a:c):a'):as')-rest (' ':s) as         = rest s as-rest (v  :s) ((c:a):as) = if isAlpha v then rest s (((Sym v:c):a):as)-                          else if null as then (a2re (c:a),v:s)-			  else wrong-			      -a2re :: [[RE]] -> RE-a2re = alt . reverse . map (cat . reverse)--wrong = error "unreadable RE"--instance Show RE where-  show Emp      = "0"-  show Lam      = "1"-  show (Sym c)  = [c]-  show (Alt xs) = concat (intersperse "+" (map show xs))-  show (Cat xs) = concatMap (showBrackIf isAlt) xs-  show (Rep x)  = showBrackIf (\x -> isCat x || isAlt x) x ++ "*"--showBrackIf p x = ['(' | q] ++ show x ++ [')' | q] where q = p x--instance Serial RE where-  series = cons0 Emp-        \/ cons0 Lam-        \/ cons1 Sym . depth 0-        \/ cons1 alt-        \/ cons1 cat-        \/ cons1 Rep--prop_readShow :: RE -> Bool-prop_readShow re = read (show re) == re--main = smallCheck 4 prop_readShow
− examples/run-examples.sh
@@ -1,3 +0,0 @@-find -iname '*.hs' \-     -exec grep -q ^main {} \; \-     -exec runghc {} \;
smallcheck.cabal view
@@ -1,9 +1,9 @@ Name:          smallcheck-Version:       0.6.2+Version:       1.0 Cabal-Version: >= 1.6 License:       BSD3 License-File:  LICENSE-Author:        Colin Runciman+Author:        Colin Runciman, Roman Cheplyaka Maintainer:    Roman Cheplyaka <roma@ro-che.info> Homepage:      https://github.com/feuerbach/smallcheck Bug-reports:   https://github.com/feuerbach/smallcheck/issues@@ -16,19 +16,7 @@                automatically by SmallCheck. Build-Type:    Simple -Extra-source-files: examples/numeric/NumProps.hs, examples/logical/LogicProps.hs,-                    examples/imperative/Interpreter.hs, examples/imperative/Syntax.hs,-                    examples/imperative/Machine.hs, examples/imperative/Behaviour.hs,-                    examples/imperative/Properties.hs, examples/imperative/Value.hs,-                    examples/imperative/StackMap.hs, examples/imperative/Compiler.hs,-                    examples/listy/ListProps.hs, examples/regular/Regular.hs,-                    examples/circuits/BitAdd.hs, examples/circuits/Mux.hs, examples/circuits/Sad.hs,-                    examples/binarytries/BinaryTries.hs,-                    examples/numeric/README, examples/logical/README, examples/imperative/README,-                    examples/listy/README, examples/regular/README, examples/circuits/README,-                    examples/binarytries/README,-                    README.md, CREDITS.md, CHANGES.md,-                    examples/run-examples.sh+Extra-source-files: README.md, CREDITS.md, CHANGES.md   @@ -39,18 +27,17 @@ Source-repository this   type:     git   location: git://github.com/feuerbach/smallcheck.git-  tag:      v0.6.2+  tag:      v1.0  Library -    Build-Depends: base == 4.*+    Build-Depends: base == 4.*, mtl, logict, ghc-prim >= 0.2, pretty      Exposed-modules:         Test.SmallCheck         Test.SmallCheck.Drivers-        Test.SmallCheck.Property         Test.SmallCheck.Series--    if impl(ghc >= 7.2.1)-      cpp-options: -DGENERICS-      build-depends: ghc-prim >= 0.2, dlist >= 0.2 && < 0.6+    Other-modules:+        Test.SmallCheck.Property+        Test.SmallCheck.SeriesMonad+        Test.SmallCheck.Property.Result