quickcheck-classes 0.4.10 → 0.4.11
raw patch · 12 files changed
+406/−76 lines, 12 filesdep +semiringsdep ~primitive
Dependencies added: semirings
Dependency ranges changed: primitive
Files
- README.md +93/−0
- changelog.md +9/−0
- quickcheck-classes.cabal +12/−2
- src/Test/QuickCheck/Classes.hs +96/−21
- src/Test/QuickCheck/Classes/Applicative.hs +9/−9
- src/Test/QuickCheck/Classes/Bits.hs +3/−3
- src/Test/QuickCheck/Classes/Common.hs +30/−25
- src/Test/QuickCheck/Classes/Foldable.hs +10/−10
- src/Test/QuickCheck/Classes/Monad.hs +2/−2
- src/Test/QuickCheck/Classes/Monoid.hs +1/−1
- src/Test/QuickCheck/Classes/Semiring.hs +141/−0
- test/Spec.hs +0/−3
README.md view
@@ -1,1 +1,94 @@ # quickcheck-classes++This library provides sets of properties that should hold for common typeclasses,+along with three (3) simple functions that you can use to test them.++### `lawsCheck`:++A convenience function for testing properties in GHCi.+For example, at GHCi:++```bash+>>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))+Monoid: Associative +++ OK, passed 100 tests.+Monoid: Left Identity +++ OK, passed 100 tests.+Monoid: Right Identity +++ OK, passed 100 tests.+```++Assuming that the `Arbitrary` instance for `Ordering` is good, we now+have confidence that the `Monoid` instance for `Ordering` satisfies+the monoid laws.++### `lawsCheckMany`:++A convenience function for checking multiple typeclass instances+of multiple types. Consider the following Haskell source file:++```haskell+import Data.Proxy (Proxy(..))+import Data.Map (Map)+import Data.Set (Set)++-- A 'Proxy' for 'Set' 'Int'. +setInt :: Proxy (Set Int)+setInt = Proxy++-- A 'Proxy' for 'Map' 'Int' 'Int'.+mapInt :: Proxy (Map Int Int)+mapInt = Proxy++myLaws :: Proxy a -> [Laws]+myLaws p = [eqLaws p, monoidLaws p]++namedTests :: [(String, [Laws])]+namedTests =+ [ ("Set Int", myLaws setInt)+ , ("Map Int Int", myLaws mapInt)+ ]+```++Now, in GHCi:++```bash+>>> lawsCheckMany namedTests++Testing properties for common typeclasses+-------------+-- Set Int --+-------------++Eq: Transitive +++ OK, passed 100 tests.+Eq: Symmetric +++ OK, passed 100 tests.+Eq: Reflexive +++ OK, passed 100 tests.+Monoid: Associative +++ OK, passed 100 tests.+Monoid: Left Identity +++ OK, passed 100 tests.+Monoid: Right Identity +++ OK, passed 100 tests.+Monoid: Concatenation +++ OK, passed 100 tests.++-----------------+-- Map Int Int --+-----------------++Eq: Transitive +++ OK, passed 100 tests.+Eq: Symmetric +++ OK, passed 100 tests.+Eq: Reflexive +++ OK, passed 100 tests.+Monoid: Associative +++ OK, passed 100 tests.+Monoid: Left Identity +++ OK, passed 100 tests.+Monoid: Right Identity +++ OK, passed 100 tests.+Monoid: Concatenation +++ OK, passed 100 tests.++```++### `specialisedLawsCheckMany`++A convenience function that allows one to check many typeclass+instances of the same type.++For example, in GHCi:++```bash+>>> specialisedLawsCheckMany (Proxy :: Proxy Word) [jsonLaws, showReadLaws]+ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.+ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.+Show/Read: Partial Isomorphism +++ OK, passed 100 tests.+```
changelog.md view
@@ -4,6 +4,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## [0.4.11] - 2018-05-14+### Added+- Greatly improved documentation+- `specialisedLawsCheckMany` function, a shorter way for the user+ to use `lawsCheckMany` on a single type.++### Change+- Some internal names, making it more clear what it is that they do.+ ## [0.4.10] - 2018-05-03 ### Added - Property tests for `mconcat`, `sconcat`, and `stimes`. It isn't
quickcheck-classes.cabal view
@@ -1,8 +1,8 @@ name: quickcheck-classes-version: 0.4.10+version: 0.4.11 synopsis: QuickCheck common typeclasses description:- This library provides quickcheck properties to ensure+ This library provides QuickCheck properties to ensure that typeclass instances adhere to the set of laws that they are supposed to. There are other libraries that do similar things, such as `genvalidity-hspec` and `checkers`.@@ -36,6 +36,13 @@ default: True manual: True +flag semirings+ description:+ You can disable the use of the `semirings` package using `-f-semirings`.+ .+ This may be useful for accelerating builds in sandboxes for expert users.+ default: True+ manual: True library hs-source-dirs: src@@ -61,6 +68,7 @@ Test.QuickCheck.Classes.Ord Test.QuickCheck.Classes.Prim Test.QuickCheck.Classes.Semigroup+ Test.QuickCheck.Classes.Semiring Test.QuickCheck.Classes.ShowRead Test.QuickCheck.Classes.Storable Test.QuickCheck.Classes.Traversable@@ -77,6 +85,8 @@ build-depends: aeson if flag(semigroupoids) build-depends: semigroupoids + if flag(semirings)+ build-depends: semirings >= 0.1.3 default-language: Haskell2010 test-suite test
src/Test/QuickCheck/Classes.hs view
@@ -1,27 +1,16 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE KindSignatures #-} {-# OPTIONS_GHC -Wall #-} -{-|-This library provides sets of properties that should hold for common typeclasses.-All of these take a 'Proxy' argument that is used to nail down the type for which-the typeclass dictionaries should be tested. For example, at GHCi:->>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))-Monoid: Associative +++ OK, passed 100 tests.-Monoid: Left Identity +++ OK, passed 100 tests.-Monoid: Right Identity +++ OK, passed 100 tests.-Assuming that the 'Arbitrary' instance for 'Ordering' is good, we now-have confidence that the 'Monoid' instance for 'Ordering' satisfies-the monoid laws. We can check multiple typeclasses with:->>> foldMap (lawsCheck . ($ (Proxy :: Proxy Word))) [jsonLaws,showReadLaws]-ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.-ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.-Show/Read: Partial Isomorphism +++ OK, passed 100 tests.+{-| This library provides sets of properties that should hold for common+ typeclasses. -} module Test.QuickCheck.Classes ( -- * Running lawsCheck , lawsCheckMany+ , specialisedLawsCheckMany -- * Properties -- ** Ground types #if MIN_VERSION_base(4,7,0)@@ -61,6 +50,8 @@ #endif -- * Types , Laws(..)+ , Proxy1(..)+ , Proxy2(..) ) where --@@ -110,30 +101,105 @@ -- import Test.QuickCheck import Test.QuickCheck.Classes.Common (foldMapA, Laws(..))+import Data.Foldable import Data.Monoid (Monoid(..))+import Data.Proxy (Proxy(..)) import Data.Semigroup (Semigroup)+import qualified Data.List as List import qualified Data.Semigroup as SG -- | A convenience function for testing properties in GHCi.--- See the test suite of this library for an example of how to--- integrate multiple properties into larger test suite.+-- For example, at GHCi:+--+-- >>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))+-- Monoid: Associative +++ OK, passed 100 tests.+-- Monoid: Left Identity +++ OK, passed 100 tests.+-- Monoid: Right Identity +++ OK, passed 100 tests.+--+-- Assuming that the 'Arbitrary' instance for 'Ordering' is good, we now+-- have confidence that the 'Monoid' instance for 'Ordering' satisfies+-- the monoid laws. lawsCheck :: Laws -> IO () lawsCheck (Laws className properties) = do flip foldMapA properties $ \(name,p) -> do putStr (className ++ ": " ++ name ++ " ") quickCheck p +-- | A convenience function that allows one to check many typeclass+-- instances of the same type.+--+-- >>> specialisedLawsCheckMany (Proxy :: Proxy Word) [jsonLaws, showReadLaws]+-- ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.+-- ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.+-- Show/Read: Partial Isomorphism +++ OK, passed 100 tests.+specialisedLawsCheckMany :: Proxy a -> [Proxy a -> Laws] -> IO ()+specialisedLawsCheckMany p ls = foldMap (lawsCheck . ($ p)) ls+ -- | A convenience function for checking multiple typeclass instances--- of multiple types.+-- of multiple types. Consider the following Haskell source file:+--+-- @+-- import Data.Proxy (Proxy(..))+-- import Data.Map (Map)+-- import Data.Set (Set)+--+-- -- A 'Proxy' for 'Set' 'Int'. +-- setInt :: Proxy (Set Int)+-- setInt = Proxy+-- +-- -- A 'Proxy' for 'Map' 'Int' 'Int'.+-- mapInt :: Proxy (Map Int Int)+-- mapInt = Proxy+-- +-- myLaws :: Proxy a -> [Laws]+-- myLaws p = [eqLaws p, monoidLaws p]+--+-- namedTests :: [(String, [Laws])]+-- namedTests =+-- [ ("Set Int", myLaws setInt)+-- , ("Map Int Int", myLaws mapInt)+-- ]+-- @+-- +-- Now, in GHCi:+--+-- >>> lawsCheckMany namedTests+--+-- @+-- Testing properties for common typeclasses+-- -------------+-- -- Set Int --+-- -------------+-- +-- Eq: Transitive +++ OK, passed 100 tests.+-- Eq: Symmetric +++ OK, passed 100 tests.+-- Eq: Reflexive +++ OK, passed 100 tests.+-- Monoid: Associative +++ OK, passed 100 tests.+-- Monoid: Left Identity +++ OK, passed 100 tests.+-- Monoid: Right Identity +++ OK, passed 100 tests.+-- Monoid: Concatenation +++ OK, passed 100 tests.+-- +-- -----------------+-- -- Map Int Int --+-- -----------------+-- +-- Eq: Transitive +++ OK, passed 100 tests.+-- Eq: Symmetric +++ OK, passed 100 tests.+-- Eq: Reflexive +++ OK, passed 100 tests.+-- Monoid: Associative +++ OK, passed 100 tests.+-- Monoid: Left Identity +++ OK, passed 100 tests.+-- Monoid: Right Identity +++ OK, passed 100 tests.+-- Monoid: Concatenation +++ OK, passed 100 tests.+-- @ lawsCheckMany :: [(String,[Laws])] -- ^ Element is type name paired with typeclass laws -> IO () lawsCheckMany xs = do putStrLn "Testing properties for common typeclasses" r <- flip foldMapA xs $ \(typeName,laws) -> do- putStrLn $ "------------"- putStrLn $ "-- " ++ typeName- putStrLn $ "------------"+ putStrLn $ List.replicate (length typeName + 6) '-'+ putStrLn $ "-- " ++ typeName ++ " --"+ putStrLn $ List.replicate (length typeName + 6) '-' flip foldMapA laws $ \(Laws typeClassName properties) -> do flip foldMapA properties $ \(name,p) -> do putStr (typeClassName ++ ": " ++ name ++ " ")@@ -155,3 +221,12 @@ instance Monoid Status where mempty = Good mappend = (SG.<>)++-- | In older versions of GHC, Proxy is not poly-kinded,+-- so we provide Proxy1.+data Proxy1 (f :: * -> *) = Proxy1++-- | In older versions of GHC, Proxy is not poly-kinded,+-- so we provide Proxy2.+data Proxy2 (f :: * -> * -> *) = Proxy2+
src/Test/QuickCheck/Classes/Applicative.hs view
@@ -52,24 +52,24 @@ applicativeIdentity _ = property $ \(Apply (a :: f Integer)) -> eq1 (pure id <*> a) a applicativeComposition :: forall proxy f. (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property-applicativeComposition _ = property $ \(Apply (u' :: f Equation)) (Apply (v' :: f Equation)) (Apply (w :: f Integer)) ->- let u = fmap runEquation u'- v = fmap runEquation v'+applicativeComposition _ = property $ \(Apply (u' :: f QuadraticEquation)) (Apply (v' :: f QuadraticEquation)) (Apply (w :: f Integer)) ->+ let u = fmap runQuadraticEquation u'+ v = fmap runQuadraticEquation v' in eq1 (pure (.) <*> u <*> v <*> w) (u <*> (v <*> w)) applicativeHomomorphism :: forall proxy f. (Applicative f, Eq1 f, Show1 f) => proxy f -> Property-applicativeHomomorphism _ = property $ \(e :: Equation) (a :: Integer) ->- let f = runEquation e+applicativeHomomorphism _ = property $ \(e :: QuadraticEquation) (a :: Integer) ->+ let f = runQuadraticEquation e in eq1 (pure f <*> pure a) (pure (f a) :: f Integer) applicativeInterchange :: forall proxy f. (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property-applicativeInterchange _ = property $ \(Apply (u' :: f Equation)) (y :: Integer) ->- let u = fmap runEquation u'+applicativeInterchange _ = property $ \(Apply (u' :: f QuadraticEquation)) (y :: Integer) ->+ let u = fmap runQuadraticEquation u' in eq1 (u <*> pure y) (pure ($ y) <*> u) applicativeLiftA2_1 :: forall proxy f. (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property-applicativeLiftA2_1 _ = property $ \(Apply (f' :: f Equation)) (Apply (x :: f Integer)) ->- let f = fmap runEquation f'+applicativeLiftA2_1 _ = property $ \(Apply (f' :: f QuadraticEquation)) (Apply (x :: f Integer)) ->+ let f = fmap runQuadraticEquation f' in eq1 (liftA2 id f x) (f <*> x) #endif
src/Test/QuickCheck/Classes/Bits.hs view
@@ -133,10 +133,10 @@ bitsClearZero :: forall a. (Bits a, Arbitrary a, Show a) => Proxy a -> Property bitsClearZero _ = myForAllShrink False (const True) (\(n :: a) -> ["n = " ++ show n])- "complement (complement n)"- (\n -> complement (complement n))+ "clearBit zeroBits n"+ (\n -> clearBit n zeroBits) "n"- (\n -> n)+ (\_ -> zeroBits) bitsSetZero :: forall a. (FiniteBits a, Arbitrary a, Show a) => Proxy a -> Property bitsSetZero _ = myForAllShrink True (const True)
src/Test/QuickCheck/Classes/Common.hs view
@@ -21,8 +21,8 @@ #if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0) , LinearEquationM(..) #endif- , Equation(..)- , EquationTwo(..)+ , QuadraticEquation(..)+ , LinearEquationTwo(..) #if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0) , nestedEq1 , propNestedEq1@@ -45,8 +45,8 @@ #if MIN_VERSION_base(4,8,0) || MIN_VERSION_transformers(0,5,0) , runLinearEquationM #endif- , runEquation- , runEquationTwo+ , runQuadraticEquation+ , runLinearEquationTwo ) where import Control.Applicative@@ -353,44 +353,49 @@ in map (\(x,y) -> LinearEquation (abs x) (abs y)) xs -- this is a quadratic equation-data Equation = Equation Integer Integer Integer+data QuadraticEquation = QuadraticEquation+ { _quadraticEquationQuadratic :: Integer+ , _quadraticEquationLinear :: Integer+ , _quadraticEquationConstant :: Integer+ } deriving (Eq) -- This show instance is does not actually provide a -- way to create an equation. Instead, it makes it look -- like a lambda.-instance Show Equation where- show (Equation a b c) = "\\x -> " ++ show a ++ " * x ^ 2 + " ++ show b ++ " * x + " ++ show c+instance Show QuadraticEquation where+ show (QuadraticEquation a b c) = "\\x -> " ++ show a ++ " * x ^ 2 + " ++ show b ++ " * x + " ++ show c -instance Arbitrary Equation where+instance Arbitrary QuadraticEquation where arbitrary = do (a,b,c) <- arbitrary- return (Equation (abs a) (abs b) (abs c))- shrink (Equation a b c) =+ return (QuadraticEquation (abs a) (abs b) (abs c))+ shrink (QuadraticEquation a b c) = let xs = shrink (a,b,c)- in map (\(x,y,z) -> Equation (abs x) (abs y) (abs z)) xs+ in map (\(x,y,z) -> QuadraticEquation (abs x) (abs y) (abs z)) xs -runEquation :: Equation -> Integer -> Integer-runEquation (Equation a b c) x = a * x ^ (2 :: Integer) + b * x + c+runQuadraticEquation :: QuadraticEquation -> Integer -> Integer+runQuadraticEquation (QuadraticEquation a b c) x = a * x ^ (2 :: Integer) + b * x + c --- linear equation of two variables-data EquationTwo = EquationTwo Integer Integer+data LinearEquationTwo = LinearEquationTwo+ { _linearEquationTwoX :: Integer+ , _linearEquationTwoY :: Integer+ } deriving (Eq) -- This show instance does not actually provide a--- way to create an EquationTwo. Instead, it makes it look+-- way to create a LinearEquationTwo. Instead, it makes it look -- like a lambda that takes two variables.-instance Show EquationTwo where- show (EquationTwo a b) = "\\x y -> " ++ show a ++ " * x + " ++ show b ++ " * y"+instance Show LinearEquationTwo where+ show (LinearEquationTwo a b) = "\\x y -> " ++ show a ++ " * x + " ++ show b ++ " * y" -instance Arbitrary EquationTwo where+instance Arbitrary LinearEquationTwo where arbitrary = do (a,b) <- arbitrary- return (EquationTwo (abs a) (abs b))- shrink (EquationTwo a b) =+ return (LinearEquationTwo (abs a) (abs b))+ shrink (LinearEquationTwo a b) = let xs = shrink (a,b)- in map (\(x,y) -> EquationTwo (abs x) (abs y)) xs--runEquationTwo :: EquationTwo -> Integer -> Integer -> Integer-runEquationTwo (EquationTwo a b) x y = a * x + b * y+ in map (\(x,y) -> LinearEquationTwo (abs x) (abs y)) xs +runLinearEquationTwo :: LinearEquationTwo -> Integer -> Integer -> Integer+runLinearEquationTwo (LinearEquationTwo a b) x y = a * x + b * y
src/Test/QuickCheck/Classes/Foldable.hs view
@@ -67,28 +67,28 @@ foldableLawsInternal p = Laws "Foldable" [ (,) "fold" $ property $ \(Apply (a :: f (SG.Sum Integer))) -> F.fold a == F.foldMap id a- , (,) "foldMap" $ property $ \(Apply (a :: f Integer)) (e :: Equation) ->- let f = SG.Sum . runEquation e+ , (,) "foldMap" $ property $ \(Apply (a :: f Integer)) (e :: QuadraticEquation) ->+ let f = SG.Sum . runQuadraticEquation e in F.foldMap f a == F.foldr (mappend . f) mempty a- , (,) "foldr" $ property $ \(e :: EquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->- let f = runEquationTwo e+ , (,) "foldr" $ property $ \(e :: LinearEquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->+ let f = runLinearEquationTwo e in F.foldr f z t == SG.appEndo (foldMap (SG.Endo . f) t) z , (,) "foldr'" (foldableFoldr' p)- , (,) "foldl" $ property $ \(e :: EquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->- let f = runEquationTwo e+ , (,) "foldl" $ property $ \(e :: LinearEquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->+ let f = runLinearEquationTwo e in F.foldl f z t == SG.appEndo (SG.getDual (F.foldMap (SG.Dual . SG.Endo . flip f) t)) z , (,) "foldl'" (foldableFoldl' p)- , (,) "foldl1" $ property $ \(e :: EquationTwo) (Apply (t :: f Integer)) ->+ , (,) "foldl1" $ property $ \(e :: LinearEquationTwo) (Apply (t :: f Integer)) -> case compatToList t of [] -> True x : xs ->- let f = runEquationTwo e+ let f = runLinearEquationTwo e in F.foldl1 f t == F.foldl f x xs- , (,) "foldr1" $ property $ \(e :: EquationTwo) (Apply (t :: f Integer)) ->+ , (,) "foldr1" $ property $ \(e :: LinearEquationTwo) (Apply (t :: f Integer)) -> case unsnoc (compatToList t) of Nothing -> True Just (xs,x) ->- let f = runEquationTwo e+ let f = runLinearEquationTwo e in F.foldr1 f t == F.foldr f x xs , (,) "toList" $ property $ \(Apply (t :: f Integer)) -> eq1 (F.toList t) (F.foldr (:) [] t)
src/Test/QuickCheck/Classes/Monad.hs view
@@ -68,8 +68,8 @@ eq1 (return x) (pure x :: f Integer) monadAp :: forall proxy f. (Monad f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property-monadAp _ = property $ \(Apply (f' :: f Equation)) (Apply (x :: f Integer)) ->- let f = fmap runEquation f'+monadAp _ = property $ \(Apply (f' :: f QuadraticEquation)) (Apply (x :: f Integer)) ->+ let f = fmap runQuadraticEquation f' in eq1 (ap f x) (f <*> x) #endif
src/Test/QuickCheck/Classes/Monoid.hs view
@@ -32,7 +32,7 @@ , ("Concatenation", monoidConcatenation p) ] --- | Tests everything from 'monoidProps' plus the following:+-- | Tests everything from 'monoidLaws' plus the following: -- -- [/Commutative/] -- @mappend a b ≡ mappend b a@
+ src/Test/QuickCheck/Classes/Semiring.hs view
@@ -0,0 +1,141 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}++{-# OPTIONS_GHC -Wall #-}++module Test.QuickCheck.Classes.Semiring+ ( +#if defined(VERSION_semirings)+ semiringLaws+#endif+ ) where++#if defined(VERSION_semirings)+import Data.Semiring+import Prelude hiding (Num(..))+#endif++import Data.Proxy (Proxy)+import Test.QuickCheck hiding ((.&.))+import Test.QuickCheck.Property (Property)++import Test.QuickCheck.Classes.Common (Laws(..), myForAllShrink)++#if defined(VERSION_semirings)+-- | Tests the following properties:+--+-- [/Additive Commutativity/]+-- @a + b ≡ b + a@+-- [/Additive Left Identity/]+-- @0 + a ≡ a@+-- [/Additive Right Identity/]+-- @a + 0 ≡ a@+-- [/Multiplicative Associativity/]+-- @a * (b * c) ≡ (a * b) * c@+-- [/Multiplicative Left Identity/]+-- @1 * a ≡ a@+-- [/Multiplicative Right Identity/]+-- @a * 1 ≡ a@+-- [/Multiplication Left Distributes Over Addition/]+-- @a * (b + c) ≡ (a * b) + (a * c)@+-- [/Multiplication Right Distributes Over Addition/]+-- @(a + b) * c ≡ (a * c) + (b * c)@+-- [/Multiplicative Left Annihilation/]+-- @0 * a ≡ 0@+-- [/Multiplicative Right Annihilation/]+-- @a * 0 ≡ 0@+semiringLaws :: (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws+semiringLaws p = Laws "Semiring"+ [ ("Additive Commutativity", semiringCommutativePlus p)+ , ("Additive Left Identity", semiringLeftIdentityPlus p)+ , ("Additive Right Identity", semiringRightIdentityPlus p)+ , ("Multiplicative Associativity", semiringAssociativeTimes p)+ , ("Multiplicative Left Identity", semiringLeftIdentityTimes p)+ , ("Multiplicative Right Identity", semiringRightIdentityTimes p)+ , ("Multiplication Left Distributes Over Addition", semiringLeftMultiplicationDistributes p)+ , ("Multiplication Right Distributes Over Addition", semiringRightMultiplicationDistributes p)+ , ("Multiplicative Left Annihilation", semiringLeftAnnihilation p)+ , ("Multiplicative Right Annihilation", semiringRightAnnihilation p)+ ]++semiringLeftMultiplicationDistributes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringLeftMultiplicationDistributes _ = myForAllShrink True (const True)+ (\(a :: a,b,c) -> ["a = " ++ show a, "b = " ++ show b, "c = " ++ show c])+ "a * (b + c)"+ (\(a,b,c) -> a * (b + c))+ "(a * b) + (a * c)"+ (\(a,b,c) -> (a * b) + (a * c))++semiringRightMultiplicationDistributes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringRightMultiplicationDistributes _ = myForAllShrink True (const True)+ (\(a :: a,b,c) -> ["a = " ++ show a, "b = " ++ show b, "c = " ++ show c])+ "(a + b) * c"+ (\(a,b,c) -> c * (a + b))+ "(a * c) + (b * c)"+ (\(a,b,c) -> (a * c) + (b * c))++semiringLeftIdentityPlus :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringLeftIdentityPlus _ = myForAllShrink False (const True)+ (\(a :: a) -> ["a = " ++ show a])+ "0 + a"+ (\a -> zero + a)+ "a"+ (\a -> a)++semiringRightIdentityPlus :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringRightIdentityPlus _ = myForAllShrink False (const True)+ (\(a :: a) -> ["a = " ++ show a])+ "a + 0"+ (\a -> a + zero)+ "a"+ (\a -> a)++semiringRightIdentityTimes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringRightIdentityTimes _ = myForAllShrink False (const True)+ (\(a :: a) -> ["a = " ++ show a])+ "a * 1"+ (\a -> a * one)+ "a"+ (\a -> a)++semiringLeftIdentityTimes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringLeftIdentityTimes _ = myForAllShrink False (const True)+ (\(a :: a) -> ["a = " ++ show a])+ "1 * a"+ (\a -> one * a)+ "a"+ (\a -> a)++semiringLeftAnnihilation :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringLeftAnnihilation _ = myForAllShrink False (const True)+ (\(a :: a) -> ["a = " ++ show a])+ "0 * a"+ (\a -> zero * a)+ "0"+ (\_ -> zero)++semiringRightAnnihilation :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringRightAnnihilation _ = myForAllShrink False (const True)+ (\(a :: a) -> ["a = " ++ show a])+ "a * 0"+ (\a -> a * zero)+ "0"+ (\_ -> zero)++semiringCommutativePlus :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringCommutativePlus _ = myForAllShrink True (const True)+ (\(a :: a,b) -> ["a = " ++ show a, "b = " ++ show b])+ "a + b"+ (\(a,b) -> a + b)+ "b + a"+ (\(a,b) -> b + a)++semiringAssociativeTimes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property+semiringAssociativeTimes _ = myForAllShrink True (const True)+ (\(a :: a,b,c) -> ["a = " ++ show a, "b = " ++ show b, "c = " ++ show c])+ "a * (b * c)"+ (\(a,b,c) -> a * (b * c))+ "(a * b) * c"+ (\(a,b,c) -> (a * b) * c)++#endif
test/Spec.hs view
@@ -33,9 +33,6 @@ main :: IO () main = lawsCheckMany allPropsApplied --- Only needed to make GHC 7.4 content.-data Proxy1 (f :: * -> *) = Proxy1- allPropsApplied :: [(String,[Laws])] allPropsApplied = [ ("Int",allLaws (Proxy :: Proxy Int))