Safe Haskell | None |
---|---|
Language | Haskell2010 |
This library provides sets of properties that should hold for common typeclasses.
Synopsis
- lawsCheck :: Laws -> IO ()
- lawsCheckMany :: [(String, [Laws])] -> IO ()
- lawsCheckOne :: Proxy a -> [Proxy a -> Laws] -> IO ()
- specialisedLawsCheckMany :: Proxy a -> [Proxy a -> Laws] -> IO ()
- bitsLaws :: (FiniteBits a, Arbitrary a, Show a) => Proxy a -> Laws
- eqLaws :: (Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- integralLaws :: (Integral a, Arbitrary a, Show a) => Proxy a -> Laws
- isListLaws :: (IsList a, Show a, Show (Item a), Arbitrary a, Arbitrary (Item a), Eq a) => Proxy a -> Laws
- jsonLaws :: (ToJSON a, FromJSON a, Show a, Arbitrary a, Eq a) => Proxy a -> Laws
- monoidLaws :: (Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- commutativeMonoidLaws :: (Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- ordLaws :: (Ord a, Arbitrary a, Show a) => Proxy a -> Laws
- enumLaws :: (Enum a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- boundedEnumLaws :: (Enum a, Bounded a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- primLaws :: (Prim a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- semigroupLaws :: (Semigroup a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- commutativeSemigroupLaws :: (Semigroup a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- semiringLaws :: (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- showReadLaws :: (Show a, Read a, Eq a, Arbitrary a) => Proxy a -> Laws
- storableLaws :: (Storable a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
- alternativeLaws :: (Alternative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- altLaws :: (Alt f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- applyLaws :: (Apply f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- applicativeLaws :: (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- bifunctorLaws :: (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f) => proxy f -> Laws
- categoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws
- commutativeCategoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws
- foldableLaws :: (Foldable f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- functorLaws :: (Functor f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- monadLaws :: (Monad f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- monadPlusLaws :: (MonadPlus f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- monadZipLaws :: (MonadZip f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- plusLaws :: (Plus f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- extendedPlusLaws :: (Plus f, Alternative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- semigroupoidLaws :: (Semigroupoid sem, Eq2 sem, Show2 sem, Arbitrary2 sem) => proxy sem -> Laws
- commutativeSemigroupoidLaws :: (Semigroupoid sem, Eq2 sem, Show2 sem, Arbitrary2 sem) => proxy sem -> Laws
- traversableLaws :: (Traversable f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
- data Laws = Laws {
- lawsTypeclass :: String
- lawsProperties :: [(String, Property)]
- data Proxy1 (f :: * -> *) = Proxy1
- data Proxy2 (f :: * -> * -> *) = Proxy2
Running
lawsCheck :: Laws -> IO () Source #
A convenience function for testing properties in GHCi. 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.
A convenience function for checking multiple typeclass instances of multiple types. Consider the following Haskell source file:
import Data.Proxy (Proxy(..)) import Data.Map (Map) import Data.Set (Set) -- AProxy
forSet
Int
. setInt :: Proxy (Set Int) setInt = Proxy -- AProxy
forMap
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.
lawsCheckOne :: Proxy a -> [Proxy a -> Laws] -> IO () Source #
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 () Source #
Deprecated: Use the better-named lawsCheckOne
instead
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.
Properties
Ground types
bitsLaws :: (FiniteBits a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following properties:
- Conjunction Idempotence
n .&. n ≡ n
- Disjunction Idempotence
n .|. n ≡ n
- Double Complement
complement (complement n) ≡ n
- Set Bit
setBit n i ≡ n .|. bit i
- Clear Bit
clearBit n i ≡ n .&. complement (bit i)
- Complement Bit
complementBit n i ≡ xor n (bit i)
- Clear Zero
clearBit zeroBits i ≡ zeroBits
- Set Zero
setBit zeroBits i ≡ bit i
- Test Zero
testBit zeroBits i ≡ False
- Pop Zero
popCount zeroBits ≡ 0
- Count Leading Zeros of Zero
countLeadingZeros zeroBits ≡ finiteBitSize ⊥
- Count Trailing Zeros of Zero
countTrailingZeros zeroBits ≡ finiteBitSize ⊥
All of the useful instances of the Bits
typeclass
also have FiniteBits
instances, so these property
tests actually require that instance as well.
Note: This property test is only available when
using base-4.7
or newer.
eqLaws :: (Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following properties:
- Transitive
a == b ∧ b == c ⇒ a == c
- Symmetric
a == b ⇒ b == a
- Reflexive
a == a
Some of these properties involve implication. In the case that the left hand side of the implication arrow does not hold, we do not retry. Consequently, these properties only end up being useful when the data type has a small number of inhabitants.
integralLaws :: (Integral a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following properties:
- Quotient Remainder
(quot x y) * y + (rem x y) ≡ x
- Division Modulus
(div x y) * y + (mod x y) ≡ x
- Integer Roundtrip
fromInteger (toInteger x) ≡ x
isListLaws :: (IsList a, Show a, Show (Item a), Arbitrary a, Arbitrary (Item a), Eq a) => Proxy a -> Laws Source #
Tests the following properties:
- Partial Isomorphism
fromList . toList ≡ id
- Length Preservation
fromList xs ≡ fromListN (length xs) xs
Note: This property test is only available when
using base-4.7
or newer.
jsonLaws :: (ToJSON a, FromJSON a, Show a, Arbitrary a, Eq a) => Proxy a -> Laws Source #
Tests the following properties:
- Partial Isomorphism
decode . encode ≡ Just
- Encoding Equals Value
decode . encode ≡ Just . toJSON
Note that in the second property, the type of decode is ByteString -> Value
,
not ByteString -> a
monoidLaws :: (Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following properties:
- Associative
mappend a (mappend b c) ≡ mappend (mappend a b) c
- Left Identity
mappend mempty a ≡ a
- Right Identity
mappend a mempty ≡ a
- Concatenation
mconcat as ≡ foldr mappend mempty as
commutativeMonoidLaws :: (Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests everything from monoidLaws
plus the following:
- Commutative
mappend a b ≡ mappend b a
ordLaws :: (Ord a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following properties:
- Antisymmetry
a ≤ b ∧ b ≤ a ⇒ a = b
- Transitivity
a ≤ b ∧ b ≤ c ⇒ a ≤ c
- Totality
a ≤ b ∨ a > b
enumLaws :: (Enum a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following properties:
- Succ Pred Identity
succ (pred x) ≡ x
- Pred Succ Identity
pred (succ x) ≡ x
This only works for Enum
types that are not bounded, meaning
that succ
and pred
must be total. This means that these property
tests work correctly for types like Integer
but not for Int
.
Sadly, there is not a good way to test fromEnum
and toEnum
,
since many types that have reasonable implementations for succ
and pred
have more inhabitants than Int
does.
primLaws :: (Prim a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Test that a Prim
instance obey the several laws.
commutativeSemigroupLaws :: (Semigroup a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests everything from semigroupLaws
, plus the following:
semiringLaws :: (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
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
storableLaws :: (Storable a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws Source #
Tests the following alternative properties:
- Set-Get
runST
(pokeElemOff
ptr ix a >>peekElemOff
ptr ix') ≡ a- Get-Set
runST
(peekElemOff
ptr ix >>pokeElemOff
ptr ix a) ≡ a
Higher-Kinded Types
alternativeLaws :: (Alternative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
applicativeLaws :: (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
bifunctorLaws :: (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f) => proxy f -> Laws Source #
categoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws Source #
commutativeCategoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws Source #
Test everything from categoryLaws
plus the following:
Note: This property test is only available when this package is built with
base-4.9+
or transformers-0.5+
.
foldableLaws :: (Foldable f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
Tests the following Foldable
properties:
- fold
fold
≡foldMap
id
- foldMap
foldMap
f ≡foldr
(mappend
. f)mempty
- foldr
foldr
f z t ≡appEndo
(foldMap
(Endo
. f) t ) z- foldr'
foldr'
f z0 xs ≡ let f' k x z = k$!
f x z infoldl
f'id
xs z0- foldr1
foldr1
f t ≡ letJust
(xs,x) =unsnoc
(toList
t) infoldr
f x xs- foldl
foldl
f z t ≡appEndo
(getDual
(foldMap
(Dual
.Endo
.flip
f) t)) z- foldl'
foldl'
f z0 xs ≡ let f' x k z = k$!
f z x infoldr
f'id
xs z0- foldl1
foldl1
f t ≡ let x : xs =toList
t infoldl
f x xs- toList
toList
≡foldr
(:) []- null
null
≡foldr
(const
(const
False
))True
- length
length
≡getSum
.foldMap
(const
(Sum
1))
Note that this checks to ensure that foldl'
and foldr'
are suitably strict.
functorLaws :: (Functor f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
monadLaws :: (Monad f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
monadPlusLaws :: (MonadPlus f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
monadZipLaws :: (MonadZip f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
extendedPlusLaws :: (Plus f, Alternative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
semigroupoidLaws :: (Semigroupoid sem, Eq2 sem, Show2 sem, Arbitrary2 sem) => proxy sem -> Laws Source #
Tests the following Semigroupoid
properties:
- Associativity
f `
o'
(g `o'
h) ≡ (f `o'
g) `o'
h
Note: This property test is only available when this package is built with
base-4.9+
or transformers-0.5+
.
commutativeSemigroupoidLaws :: (Semigroupoid sem, Eq2 sem, Show2 sem, Arbitrary2 sem) => proxy sem -> Laws Source #
Tests everything from semigroupoidLaws
plus the following:
- Commutative
f `
o'
g ≡ g `o'
f
Note: This property test is only available when this package is built with
base-4.9+
or transformers-0.5+
.
traversableLaws :: (Traversable f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws Source #
Tests the following Traversable
properties:
- Naturality
t
for every applicative transformation.
traverse
f ≡traverse
(t.
f)t
- Identity
traverse
Identity
≡Identity
- Composition
traverse
(Compose
.
fmap
g.
f) ≡Compose
.
fmap
(traverse
g).
traverse
f- Sequence Naturality
t
for every applicative transformation.
sequenceA
≡sequenceA
.
fmap
tt
- Sequence Identity
sequenceA
.
fmap
Identity
≡Identity
- Sequence Composition
sequenceA
.
fmap
Compose
≡Compose
.
fmap
sequenceA
.
sequenceA
- foldMap
foldMap
≡foldMapDefault
- fmap
fmap
≡fmapDefault
Where an applicative transformation is a function
t :: (Applicative f, Applicative g) => f a -> g a
preserving the Applicative
operations, i.e.
Types
A set of laws associated with a typeclass.
Laws | |
|