Copyright | (c) 2015-2020 Rudy Matela |
---|---|

License | 3-Clause BSD (see the file LICENSE) |

Maintainer | Rudy Matela <rudy@matela.com.br> |

Safe Haskell | None |

Language | Haskell2010 |

This module is part of LeanCheck, a simple enumerative property-based testing library.

Some operators for property-based testing.

## Synopsis

- (==>) :: Bool -> Bool -> Bool
- (===) :: Eq b => (a -> b) -> (a -> b) -> a -> Bool
- (====) :: Eq c => (a -> b -> c) -> (a -> b -> c) -> a -> b -> Bool
- (&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
- (&&&&) :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
- (&&&&&) :: (a -> b -> c -> Bool) -> (a -> b -> c -> Bool) -> a -> b -> c -> Bool
- (|||) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
- (||||) :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
- isIdempotent :: Eq a => (a -> a) -> a -> Bool
- isIdentity :: Eq a => (a -> a) -> a -> Bool
- isNeverIdentity :: Eq a => (a -> a) -> a -> Bool
- isCommutative :: Eq b => (a -> a -> b) -> a -> a -> Bool
- isAssociative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool
- isDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
- isLeftDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
- isRightDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
- isFlipped :: Eq c => (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
- isTransitive :: (a -> a -> Bool) -> a -> a -> a -> Bool
- isReflexive :: (a -> a -> Bool) -> a -> Bool
- isIrreflexive :: (a -> a -> Bool) -> a -> Bool
- isSymmetric :: (a -> a -> Bool) -> a -> a -> Bool
- isAsymmetric :: (a -> a -> Bool) -> a -> a -> Bool
- isAntisymmetric :: Eq a => (a -> a -> Bool) -> a -> a -> Bool
- isEquivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool
- isPartialOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
- isStrictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
- isTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
- isStrictTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
- isComparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool
- (=$) :: Eq b => a -> (a -> b) -> a -> Bool
- ($=) :: (a -> Bool) -> a -> Bool
- (=|) :: Eq a => [a] -> Int -> [a] -> Bool
- (|=) :: (a -> Bool) -> a -> Bool
- okEq :: Eq a => a -> a -> a -> Bool
- okOrd :: Ord a => a -> a -> a -> Bool
- okEqOrd :: (Eq a, Ord a) => a -> a -> a -> Bool
- okNum :: (Eq a, Num a) => a -> a -> a -> Bool
- okNumNonNegative :: (Eq a, Num a) => a -> a -> a -> Bool
- idempotent :: Eq a => (a -> a) -> a -> Bool
- identity :: Eq a => (a -> a) -> a -> Bool
- neverIdentity :: Eq a => (a -> a) -> a -> Bool
- commutative :: Eq b => (a -> a -> b) -> a -> a -> Bool
- associative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool
- distributive :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
- symmetric2 :: Eq c => (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
- transitive :: (a -> a -> Bool) -> a -> a -> a -> Bool
- reflexive :: (a -> a -> Bool) -> a -> Bool
- irreflexive :: (a -> a -> Bool) -> a -> Bool
- symmetric :: (a -> a -> Bool) -> a -> a -> Bool
- asymmetric :: (a -> a -> Bool) -> a -> a -> Bool
- antisymmetric :: Eq a => (a -> a -> Bool) -> a -> a -> Bool
- equivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool
- partialOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
- strictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
- totalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
- strictTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
- comparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool

# Combining properties

(==>) :: Bool -> Bool -> Bool infixr 0 Source #

Boolean implication operator. Useful for defining conditional properties:

prop_something x y = condition x y ==> something x y

Examples:

> prop_addMonotonic x y = y > 0 ==> x + y > x > check prop_addMonotonic +++ OK, passed 200 tests.

(===) :: Eq b => (a -> b) -> (a -> b) -> a -> Bool infix 4 Source #

Allows building equality properties between functions.

prop_id_idempotent = id === id . id

> check $ id === (+0) +++ OK, passed 200 tests.

> check $ id === id . id +++ OK, passed 1 tests (exhausted).

> check $ id === (+1) *** Failed! Falsifiable (after 1 tests): 0

(====) :: Eq c => (a -> b -> c) -> (a -> b -> c) -> a -> b -> Bool infix 4 Source #

Allows building equality properties between two-argument functions.

> holds 100 $ const ==== asTypeOf True

> holds 100 $ (+) ==== flip (+) True

> holds 100 $ (+) ==== (*) False

(&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool infixr 3 Source #

And (`&&`

) operator over one-argument properties.

Allows building conjuntions between one-argument properties:

> holds 100 $ id === (+0) &&& id === (id . id) True

(&&&&) :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool infixr 3 Source #

And (`&&`

) operator over two-argument properties.

Allows building conjuntions between two-argument properties:

> holds 100 $ (+) ==== flip (+) &&&& (+) ==== (*) False

(&&&&&) :: (a -> b -> c -> Bool) -> (a -> b -> c -> Bool) -> a -> b -> c -> Bool infixr 3 Source #

And operator over three-argument properties.

(|||) :: (a -> Bool) -> (a -> Bool) -> a -> Bool infixr 2 Source #

Or (`||`

) operator over one-argument properties.

Allows building disjunctions between one-argument properties:

> holds 100 $ id === (+0) ||| id === (id . id) True

(||||) :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool infixr 2 Source #

Or (`||`

) operator over two-argument properties.

Allows building conjuntions between two-argument properties:

> holds 100 $ (+) ==== flip (+) |||| (+) ==== (*) True

# Properties of unary functions

isIdempotent :: Eq a => (a -> a) -> a -> Bool Source #

Is the given function idempotent? `f (f x) == x`

> check $ isIdempotent abs +++ OK, passed 200 tests.

> check $ isIdempotent sort +++ OK, passed 200 tests.

> check $ isIdempotent negate *** Failed! Falsifiable (after 2 tests): 1

isIdentity :: Eq a => (a -> a) -> a -> Bool Source #

Is the given function an identity? `f x == x`

> check $ isIdentity (+0) +++ OK, passed 200 tests.

> check $ isIdentity (sort :: [()]->[()]) +++ OK, passed 200 tests.

> check $ isIdentity (not . not) +++ OK, passed 2 tests (exhausted).

isNeverIdentity :: Eq a => (a -> a) -> a -> Bool Source #

Is the given function never an identity? `f x /= x`

> check $ neverIdentity not +++ OK, passed 2 tests (exhausted).

> check $ neverIdentity negate *** Failed! Falsifiable (after 1 tests): 0

Note: this is not the same as not being an `identity`

.

# Properties of operators (binary functions)

isCommutative :: Eq b => (a -> a -> b) -> a -> a -> Bool Source #

Is a given operator commutative? `x + y = y + x`

> check $ isCommutative (+) +++ OK, passed 200 tests.

> import Data.List > check $ isCommutative (union :: [Int]->[Int]->[Int]) *** Failed! Falsifiable (after 4 tests): [] [0,0]

isAssociative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool Source #

Is a given operator associative? `x + (y + z) = (x + y) + z`

> check $ isAssociative (+) +++ OK, passed 200 tests.

> check $ isAssociative (-) *** Failed! Falsifiable (after 2 tests): 0 0 1

isDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool Source #

Does the first operator, left-distributes over the second?

This is an alias to `isLeftDistributiveOver`

.

isLeftDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool Source #

Does the first operator, left-distributes over the second?
`x * (y + z) = (x * y) + (x * z)`

> check $ (*) `isLeftDistributiveOver` (+) +++ OK, passed 200 tests.

> check $ (+) `isLeftDistributiveOver` (*) *** Failed! Falsifiable (after 8 tests): 1 0 1

isRightDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool Source #

Does the first operator, right-distributes over the second?
`(y + z) * x = (y * x) + (z * x)`

> check $ (*) `isRightDistributiveOver` (+) +++ OK, passed 200 tests.

> check $ (+) `isRightDistributiveOver` (*) *** Failed! Falsifiable (after 8 tests): 1 0 1

isFlipped :: Eq c => (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool Source #

Are two operators `flip`

ped versions of each other?

> check $ ((<) `isFlipped` (>) :: Int -> Int -> Bool) +++ OK, passed 200 tests.

> check $ ((<=) `isFlipped` (>=) :: Int -> Int -> Bool) +++ OK, passed 200 tests.

> check $ ((<) `isFlipped` (>=) :: Int -> Int -> Bool) *** Failed! Falsifiable (after 1 tests): 0 0

> check $ ((<=) `isFlipped` (>) :: Int -> Int -> Bool) *** Failed! Falsifiable (after 1 tests): 0 0

# Properties of relations (binary functions returning truth values)

isTransitive :: (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Is a given relation transitive?

A relation is transitive when if a is related to b then b is related to c.

> check $ isTransitive ((==) :: Int->Int->Bool) +++ OK, passed 200 tests.

> check $ isTransitive ((/=) :: Int->Int->Bool) *** Failed! Falsifiable (after 3 tests): 0 1 0

isReflexive :: (a -> a -> Bool) -> a -> Bool Source #

Is a given relation reflexive?

A relation is reflexive when an element is always related to itself.

> check $ isReflexive ((==) :: Int->Int->Bool) +++ OK, passed 200 tests.

> check $ isReflexive ((/=) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0

isIrreflexive :: (a -> a -> Bool) -> a -> Bool Source #

Is a given relation irreflexive?

A given relation is irreflexive or anti-reflexive when an element is _never_ related to itself.

This is *not* the negation of `isReflexive`

.

> check $ isIrreflexive ((==) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0

> check $ isIrreflexive ((/=) :: Int->Int->Bool) +++ OK, passed 200 tests.

isSymmetric :: (a -> a -> Bool) -> a -> a -> Bool Source #

Is a given relation symmetric?

A relation is symmetric when if a is related to b, then b is related to a.

> check $ isSymmetric (&&) +++ OK, passed 4 tests (exhausted).

> check $ isSymmetric (==>) *** Failed! Falsifiable (after 2 tests): False True

This is a type-restricted version of `isCommutative`

.

isAsymmetric :: (a -> a -> Bool) -> a -> a -> Bool Source #

Is a given relation asymmetric?

Not to be confused with not `isSymmetric`

and `isAntisymmetric`

.

> check $ isAsymmetric ((<=) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0 0

> check $ isAsymmetric ((<) :: Int->Int->Bool) +++ OK, passed 200 tests.

isAntisymmetric :: Eq a => (a -> a -> Bool) -> a -> a -> Bool Source #

Is a given relation antisymmetric?

Not to be confused with `isAsymmetric`

.
Not to be confused with the negation of `isSymmetric`

.

> check $ isAntisymmetric ((<=) :: Int->Int->Bool) +++ OK, passed 200 tests.

> check $ isAntisymmetric ((/=) :: Int->Int->Bool) *** Failed! Falsifiable (after 2 tests): 0 1

# Properties of order relations

isEquivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Is the given binary relation an equivalence?

In other words, is the given relation reflexive, symmetric and transitive?

> check (isEquivalence (==) :: Int -> Int -> Int -> Bool) +++ OK, passed 200 tests.

> check (isEquivalence (<=) :: Int -> Int -> Int -> Bool) *** Failed! Falsifiable (after 3 tests): 0 1 0

Or, using Test.LeanCheck.Utils.TypeBinding:

> check $ isEquivalence (<=) -:> int *** Failed! Falsifiable (after 3 tests): 0 1 0

isPartialOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Is the given binary relation a partial order?

In other words, is the given relation reflexive, antisymmetric and transitive?

> check $ isPartialOrder ((<) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0 0 0

> check $ isPartialOrder ((<=) :: Int->Int->Bool) +++ OK, passed 200 tests.

> check $ isPartialOrder isSubsetOf +++ OK, passed 200 tests.

isStrictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Is the given binary relation a strict partial order?

In other words, is the given relation irreflexive, asymmetric and transitive?

> check $ isStrictPartialOrder ((<) :: Int->Int->Bool) +++ OK, passed 200 tests.

> check $ isStrictPartialOrder ((<=) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0 0 0

isTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Is the given binary relation a total order?

> check $ isTotalOrder ((<) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0 0 0 > check $ isTotalOrder ((<=) :: Int->Int->Bool) +++ OK, passed 200 tests.

isStrictTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Is the given binary relation a strict total order?

> check $ isStrictTotalOrder ((<=) :: Int->Int->Bool) *** Failed! Falsifiable (after 1 tests): 0 0 0

> check $ isStrictTotalOrder ((<) :: Int->Int->Bool) +++ OK, passed 200 tests.

isComparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool Source #

# Ternary comparison operators

(=$) :: Eq b => a -> (a -> b) -> a -> Bool infixl 4 Source #

Equal under, a ternary operator with the same fixity as `==`

.

x =$ f $= y = f x == f y

> [1,2,3,4,5] =$ take 2 $= [1,2,4,8,16] True

> [1,2,3,4,5] =$ take 3 $= [1,2,4,8,16] False

> [1,2,3] =$ sort $= [3,2,1] True

> 42 =$ (`mod` 10) $= 16842 True

> 42 =$ (`mod` 9) $= 16842 False

> 'a' =$ isLetter $= 'b' True

> 'a' =$ isLetter $= '1' False

(=|) :: Eq a => [a] -> Int -> [a] -> Bool infixl 4 Source #

Check if two lists are equal for `n`

values.
This operator has the same fixity of `==`

.

xs =| n |= ys = take n xs == take n ys

[1,2,3,4,5] =| 2 |= [1,2,4,8,16] -- > True [1,2,3,4,5] =| 3 |= [1,2,4,8,16] -- > False

# Properties for typeclass instances

okEq :: Eq a => a -> a -> a -> Bool Source #

Is this `Eq`

instance valid?

This is useful for testing your custom `Eq`

instances
against required properties.

In particular,
this function tests that `==`

is an equivalence
and that `/=`

is the negation of `==`

.

> check $ (okEq :: Int -> Int -> Int -> Bool) +++ OK, passed 200 tests.

> check $ (okEq :: Bool -> Bool -> Bool -> Bool) +++ OK, passed 8 tests (exhausted).

okNum :: (Eq a, Num a) => a -> a -> a -> Bool Source #

Is this `Num`

instance valid?

This is useful for testing your custom `Num`

instances
against required properties.

> check (okNum :: Int -> Int -> Int -> Bool) +++ OK, passed 200 tests.

Double is *mostly* valid, but not *entirely* valid:

> check (okNum :: Double -> Double -> Double -> Bool) *** Failed! Falsifiable (after 6 tests):

- 0 0.0 Infinity

okNumNonNegative :: (Eq a, Num a) => a -> a -> a -> Bool Source #

Like `okNum`

but restricted to zero and positives.

> check (okNumNonNegative :: Natural -> Natural -> Natural -> Bool) +++ OK, passed 200 tests.

# Deprecated functions

idempotent :: Eq a => (a -> a) -> a -> Bool Source #

Deprecated: Use isIdempotent.

Deprecated: use `isIdempotent`

.

identity :: Eq a => (a -> a) -> a -> Bool Source #

Deprecated: Use isIdentity.

Deprecated: use `isIdentity`

.

neverIdentity :: Eq a => (a -> a) -> a -> Bool Source #

Deprecated: Use isNeverIdentity.

Deprecated: use `isNeverIdentity`

.

commutative :: Eq b => (a -> a -> b) -> a -> a -> Bool Source #

Deprecated: Use isCommutative.

Deprecated: use `isCommutative`

.

associative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool Source #

Deprecated: Use isAssociative.

Deprecated: use `isAssociative`

.

distributive :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool Source #

Deprecated: Use isDistributiveOver.

Deprecated: use `isDistributiveOver`

.

symmetric2 :: Eq c => (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool Source #

Deprecated: Use isFlipped.

Deprecated: use `isFlipped`

.

transitive :: (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Deprecated: Use isTransitive.

Deprecated: use `isTransitive`

.

reflexive :: (a -> a -> Bool) -> a -> Bool Source #

Deprecated: Use isReflexive.

Deprecated: use `isReflexive`

.

irreflexive :: (a -> a -> Bool) -> a -> Bool Source #

Deprecated: Use isIrreflexive.

Deprecated: use `isIrreflexive`

.

symmetric :: (a -> a -> Bool) -> a -> a -> Bool Source #

Deprecated: Use isSymmetric.

Deprecated: use `isSymmetric`

.

asymmetric :: (a -> a -> Bool) -> a -> a -> Bool Source #

Deprecated: Use isAsymmetric.

Deprecated: use `isAsymmetric`

.

antisymmetric :: Eq a => (a -> a -> Bool) -> a -> a -> Bool Source #

Deprecated: Use isAntisymmetric.

Deprecated: use `isAntisymmetric`

.

equivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Deprecated: Use isEquivalence.

Deprecated: use `isEquivalence`

.

partialOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Deprecated: Use isPartialOrder.

Deprecated: use `isPartialOrder`

.

strictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Deprecated: Use isStrictPartialOrder.

Deprecated: use `isStrictPartialOrder`

.

totalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Deprecated: Use isTotalOrder.

Deprecated: use `isTotalOrder`

.

strictTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool Source #

Deprecated: Use isStrictTotalOrder.

Deprecated: use `isStrictTotalOrder`

.

comparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool Source #

Deprecated: Use isComparison.

Deprecated: use `isComparison`

.