-- |
-- Module      : Test.LeanCheck.Utils.Operators
-- Copyright   : (c) 2015-2020 Rudy Matela
-- License     : 3-Clause BSD  (see the file LICENSE)
-- Maintainer  : Rudy Matela <rudy@matela.com.br>
--
-- This module is part of LeanCheck,
-- a simple enumerative property-based testing library.
--
-- Some operators for property-based testing.
module Test.LeanCheck.Utils.Operators
  (

  -- * Combining properties
    (==>)
  , (===), (====)
  , (&&&), (&&&&), (&&&&&)
  , (|||), (||||)

  -- * Properties of unary functions
  , isIdempotent
  , isIdentity
  , isNeverIdentity

  -- * Properties of operators (binary functions)
  , isCommutative
  , isAssociative
  , isDistributiveOver
  , isLeftDistributiveOver
  , isRightDistributiveOver
  , isFlipped

  -- * Properties of relations (binary functions returning truth values)
  , isTransitive
  , isReflexive
  , isIrreflexive
  , isSymmetric
  , isAsymmetric
  , isAntisymmetric

  -- * Properties of order relations
  , isEquivalence
  , isPartialOrder
  , isStrictPartialOrder
  , isTotalOrder
  , isStrictTotalOrder
  , isComparison

  -- * Ternary comparison operators
  , (=$), ($=)
  , (=|), (|=)

  -- * Properties for typeclass instances
  , okEq
  , okOrd
  , okEqOrd
  , okNum
  , okNumNonNegative

  -- * Deprecated functions
  , idempotent
  , identity
  , neverIdentity
  , commutative
  , associative
  , distributive
  , symmetric2
  , transitive
  , reflexive
  , irreflexive
  , symmetric
  , asymmetric
  , antisymmetric
  , equivalence
  , partialOrder
  , strictPartialOrder
  , totalOrder
  , strictTotalOrder
  , comparison
  )
where

import Test.LeanCheck ((==>))

combine :: (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d)
combine :: (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine b -> c -> d
(?) a -> b
f a -> c
g  =  \a
x -> a -> b
f a
x b -> c -> d
? a -> c
g a
x

-- Uneeded, just food for thought:
-- > combine2 :: (c -> d -> e) -> (a -> b -> c) -> (a -> b -> d) -> (a -> b -> e)
-- Two possible implementations:
-- > combine2 op f g = \x y -> f x y `op` g x y
-- > combine2 = combine . combine

-- | 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 b => (a -> b) -> (a -> b) -> a -> Bool
=== :: (a -> b) -> (a -> b) -> a -> Bool
(===)  =  (b -> b -> Bool) -> (a -> b) -> (a -> b) -> a -> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine b -> b -> Bool
forall a. Eq a => a -> a -> Bool
(==)
infix 4 ===

-- | Allows building equality properties between two-argument functions.
--
-- > > holds 100 $ const ==== asTypeOf
-- > True
--
-- > > holds 100 $ (+) ==== flip (+)
-- > True
--
-- > > holds 100 $ (+) ==== (*)
-- > False
(====) :: Eq c => (a -> b -> c) -> (a -> b -> c) -> a -> b -> Bool
==== :: (a -> b -> c) -> (a -> b -> c) -> a -> b -> Bool
(====)  =  ((b -> c) -> (b -> c) -> b -> Bool)
-> (a -> b -> c) -> (a -> b -> c) -> a -> b -> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine (b -> c) -> (b -> c) -> b -> Bool
forall b a. Eq b => (a -> b) -> (a -> b) -> a -> Bool
(===)
infix 4 ====

-- | And ('&&') operator over one-argument properties.
--
-- Allows building conjuntions between one-argument properties:
--
-- > > holds 100 $ id === (+0) &&& id === (id . id)
-- > True
(&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
&&& :: (a -> Bool) -> (a -> Bool) -> a -> Bool
(&&&)  =  (Bool -> Bool -> Bool) -> (a -> Bool) -> (a -> Bool) -> a -> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine Bool -> Bool -> Bool
(&&)
infixr 3 &&&

-- | And ('&&') operator over two-argument properties.
--
-- Allows building conjuntions between two-argument properties:
--
-- > > holds 100 $ (+) ==== flip (+) &&&& (+) ==== (*)
-- > False
(&&&&) :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
&&&& :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
(&&&&)  =  ((b -> Bool) -> (b -> Bool) -> b -> Bool)
-> (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine (b -> Bool) -> (b -> Bool) -> b -> Bool
forall a. (a -> Bool) -> (a -> Bool) -> a -> Bool
(&&&)
infixr 3 &&&&

-- | And operator over three-argument properties.
(&&&&&) :: (a -> b -> c -> Bool) -> (a -> b -> c -> Bool) -> a -> b -> c -> Bool
&&&&& :: (a -> b -> c -> Bool)
-> (a -> b -> c -> Bool) -> a -> b -> c -> Bool
(&&&&&)  =  ((b -> c -> Bool) -> (b -> c -> Bool) -> b -> c -> Bool)
-> (a -> b -> c -> Bool)
-> (a -> b -> c -> Bool)
-> a
-> b
-> c
-> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine (b -> c -> Bool) -> (b -> c -> Bool) -> b -> c -> Bool
forall a b. (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
(&&&&)
infixr 3 &&&&&

-- | Or ('||') operator over one-argument properties.
--
-- Allows building disjunctions between one-argument properties:
--
-- > > holds 100 $ id === (+0) ||| id === (id . id)
-- > True
(|||) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
||| :: (a -> Bool) -> (a -> Bool) -> a -> Bool
(|||)  =  (Bool -> Bool -> Bool) -> (a -> Bool) -> (a -> Bool) -> a -> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine Bool -> Bool -> Bool
(||)
infixr 2 |||

-- | Or ('||') operator over two-argument properties.
--
-- Allows building conjuntions between two-argument properties:
--
-- > > holds 100 $ (+) ==== flip (+) |||| (+) ==== (*)
-- > True
(||||) :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
|||| :: (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
(||||)  =  ((b -> Bool) -> (b -> Bool) -> b -> Bool)
-> (a -> b -> Bool) -> (a -> b -> Bool) -> a -> b -> Bool
forall b c d a. (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
combine (b -> Bool) -> (b -> Bool) -> b -> Bool
forall a. (a -> Bool) -> (a -> Bool) -> a -> Bool
(|||)
infixr 2 ||||

-- | 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]
isCommutative :: Eq b => (a -> a -> b) -> a -> a -> Bool
isCommutative :: (a -> a -> b) -> a -> a -> Bool
isCommutative a -> a -> b
(?)  =  \a
x a
y -> a
x a -> a -> b
? a
y b -> b -> Bool
forall a. Eq a => a -> a -> Bool
== a
y a -> a -> b
? a
x

-- | 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
isAssociative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool
isAssociative :: (a -> a -> a) -> a -> a -> a -> Bool
isAssociative a -> a -> a
(?)  =  \a
x a
y a
z -> a
x a -> a -> a
? (a
y a -> a -> a
? a
z) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== (a
x a -> a -> a
? a
y) a -> a -> a
? a
z

-- | Does the first operator, left-distributes over the second?
--
-- This is an alias to 'isLeftDistributiveOver'.
isDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
isDistributiveOver :: (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
isDistributiveOver  =  (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
forall a.
Eq a =>
(a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
isLeftDistributiveOver

-- | 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
isLeftDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
a -> a -> a
(?) isLeftDistributiveOver :: (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
`isLeftDistributiveOver` a -> a -> a
(#)  =  \a
x a
y a
z -> a
x a -> a -> a
? (a
y a -> a -> a
# a
z) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== (a
x a -> a -> a
? a
y) a -> a -> a
# (a
x a -> a -> a
? a
z)

-- | 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
isRightDistributiveOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
a -> a -> a
(?) isRightDistributiveOver :: (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
`isRightDistributiveOver` a -> a -> a
(#)  =  \a
x a
y a
z -> (a
y a -> a -> a
# a
z) a -> a -> a
? a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== (a
y a -> a -> a
? a
x) a -> a -> a
# (a
z a -> a -> a
? a
x)

-- | 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
isFlipped :: Eq c => (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
a -> b -> c
(+-) isFlipped :: (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
`isFlipped` b -> a -> c
(-+)  =  \a
x b
y -> a
x a -> b -> c
+- b
y c -> c -> Bool
forall a. Eq a => a -> a -> Bool
== b
y b -> a -> c
-+ a
x

-- | 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
isTransitive :: (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive :: (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive a -> a -> Bool
(?)  =  \a
x a
y a
z -> a
x a -> a -> Bool
? a
y Bool -> Bool -> Bool
&& a
y a -> a -> Bool
? a
z Bool -> Bool -> Bool
==> a
x a -> a -> Bool
? a
z

-- | 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
isReflexive :: (a -> a -> Bool) -> a -> Bool
isReflexive :: (a -> a -> Bool) -> a -> Bool
isReflexive a -> a -> Bool
(?)  =  \a
x -> a
x a -> a -> Bool
? a
x

-- | 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.
isIrreflexive :: (a -> a -> Bool) -> a -> Bool
isIrreflexive :: (a -> a -> Bool) -> a -> Bool
isIrreflexive a -> a -> Bool
(?)  =  \a
x -> Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ a
x a -> a -> Bool
? a
x

-- | 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'.
isSymmetric :: (a -> a -> Bool) -> a -> a -> Bool
isSymmetric :: (a -> a -> Bool) -> a -> a -> Bool
isSymmetric  =  (a -> a -> Bool) -> a -> a -> Bool
forall b a. Eq b => (a -> a -> b) -> a -> a -> Bool
isCommutative

-- | 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
isAntisymmetric :: Eq a => (a -> a -> Bool) -> a -> a -> Bool
isAntisymmetric :: (a -> a -> Bool) -> a -> a -> Bool
isAntisymmetric a -> a -> Bool
(?)  =  \a
x a
y -> a
x a -> a -> Bool
? a
y Bool -> Bool -> Bool
&& a
y a -> a -> Bool
? a
x Bool -> Bool -> Bool
==> a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y

-- | 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.
isAsymmetric :: (a -> a -> Bool) -> a -> a -> Bool
isAsymmetric :: (a -> a -> Bool) -> a -> a -> Bool
isAsymmetric a -> a -> Bool
(?)  =  \a
x a
y -> a
x a -> a -> Bool
? a
y Bool -> Bool -> Bool
==> Bool -> Bool
not (a
y a -> a -> Bool
? a
x)

-- | 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
isEquivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool
isEquivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool
isEquivalence a -> a -> Bool
(==)  =  \a
x a
y a
z -> (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isReflexive  a -> a -> Bool
(==) a
x
                              Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> Bool
isSymmetric  a -> a -> Bool
(==) a
x a
y
                              Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive a -> a -> Bool
(==) a
x a
y a
z

-- | 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.
isPartialOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
isPartialOrder a -> a -> Bool
(<=)  =  \a
x a
y a
z -> (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isReflexive     a -> a -> Bool
(<=) a
x
                               Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> Bool
isAntisymmetric a -> a -> Bool
(<=) a
x a
y
                               Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive    a -> a -> Bool
(<=) a
x a
y a
z

-- | 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
isStrictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
isStrictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
isStrictPartialOrder a -> a -> Bool
(<)  =  \a
x a
y a
z -> (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isIrreflexive a -> a -> Bool
(<) a
x
                                    Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> Bool
isAsymmetric  a -> a -> Bool
(<) a
x a
y -- implied?
                                    Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive  a -> a -> Bool
(<) a
x a
y a
z

-- | 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.
isTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isTotalOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
isTotalOrder a -> a -> Bool
(<=)  =  \a
x a
y a
z -> (a
x a -> a -> Bool
<= a
y Bool -> Bool -> Bool
|| a
y a -> a -> Bool
<= a
x)
                             Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> Bool
isAntisymmetric a -> a -> Bool
(<=) a
x a
y
                             Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive    a -> a -> Bool
(<=) a
x a
y a
z

-- | 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.
isStrictTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isStrictTotalOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
isStrictTotalOrder a -> a -> Bool
(<)  =  \a
x a
y a
z -> (a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
y Bool -> Bool -> Bool
==> a
x a -> a -> Bool
< a
y Bool -> Bool -> Bool
|| a
y a -> a -> Bool
< a
x)
                                  Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isIrreflexive a -> a -> Bool
(<) a
x
                                  Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> Bool
isAsymmetric  a -> a -> Bool
(<) a
x a
y -- implied?
                                  Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive  a -> a -> Bool
(<) a
x a
y a
z

-- | Does the given 'compare' function follow the required properties?
--
-- This is useful for testing custom 'Ord' instances.
--
-- > > check $ isComparison (compare :: Int->Int->Ordering)
-- > +++ OK, passed 200 tests.
isComparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool
isComparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool
isComparison a -> a -> Ordering
compare  =  \a
x a
y a
z -> (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isEquivalence a -> a -> Bool
(===) a
x a
y a
z
                                Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isIrreflexive a -> a -> Bool
(<) a
x
                                Bool -> Bool -> Bool
&& (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive  a -> a -> Bool
(<) a
x a
y a
z
                                Bool -> Bool -> Bool
&& (a -> a -> Bool
(<) (a -> a -> Bool) -> (a -> a -> Bool) -> a -> a -> Bool
forall c a b.
Eq c =>
(a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
`isFlipped` a -> a -> Bool
(>)) a
x a
y
  where
  a
x === :: a -> a -> Bool
=== a
y  =  a
x a -> a -> Ordering
`compare` a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
EQ
  a
x  < :: a -> a -> Bool
<  a
y  =  a
x a -> a -> Ordering
`compare` a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT
  a
x  > :: a -> a -> Bool
>  a
y  =  a
x a -> a -> Ordering
`compare` a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT

-- | 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
isIdempotent :: Eq a => (a -> a) -> a -> Bool
isIdempotent :: (a -> a) -> a -> Bool
isIdempotent a -> a
f  =  a -> a
f (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
f (a -> a) -> (a -> a) -> a -> Bool
forall b a. Eq b => (a -> b) -> (a -> b) -> a -> Bool
=== a -> a
f

-- | 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).
isIdentity :: Eq a => (a -> a) -> a -> Bool
isIdentity :: (a -> a) -> a -> Bool
isIdentity a -> a
f  =  a -> a
f (a -> a) -> (a -> a) -> a -> Bool
forall b a. Eq b => (a -> b) -> (a -> b) -> a -> Bool
=== a -> a
forall a. a -> a
id

-- | 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'.
isNeverIdentity :: Eq a => (a -> a) -> a -> Bool
isNeverIdentity :: (a -> a) -> a -> Bool
isNeverIdentity  =  (Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((a -> Bool) -> a -> Bool)
-> ((a -> a) -> a -> Bool) -> (a -> a) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdentity

-- | 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).
okEq :: Eq a => a -> a -> a -> Bool
okEq :: a -> a -> a -> Bool
okEq a
x a
y a
z  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isEquivalence a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==) a
x a
y a
z
            Bool -> Bool -> Bool
&& (a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
y) Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Bool
not (a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y)

-- | Is this 'Ord' instance valid?
--
-- This is useful for testing your custom 'Ord' instances
-- against required properties.
--
-- > > check $ (okOrd :: Int -> Int -> Int -> Bool)
-- > +++ OK, passed 200 tests.
--
-- > > check $ (okOrd :: Bool -> Bool -> Bool -> Bool)
-- > +++ OK, passed 8 tests (exhausted).
okOrd :: Ord a => a -> a -> a -> Bool
okOrd :: a -> a -> a -> Bool
okOrd a
x a
y a
z  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isTotalOrder a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<=) a
x a
y a
z
             Bool -> Bool -> Bool
&& (a -> a -> Ordering) -> a -> a -> a -> Bool
forall a. (a -> a -> Ordering) -> a -> a -> a -> Bool
isComparison a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
x a
y a
z
             Bool -> Bool -> Bool
&& (a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
y) Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== ((a
x a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` a
y) Ordering -> [Ordering] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Ordering
LT,Ordering
EQ])

-- | Is this 'Eq' and 'Ord' instance valid and consistent?
--
-- This is useful for testing your custom 'Eq' and 'Ord' instances
-- against required properties.
--
-- > > check $ (okEqOrd :: Int -> Int -> Int -> Bool)
-- > +++ OK, passed 200 tests.
--
-- > > check $ (okEqOrd :: Bool -> Bool -> Bool -> Bool)
-- > +++ OK, passed 8 tests (exhausted).
okEqOrd :: (Eq a, Ord a) => a -> a -> a -> Bool
okEqOrd :: a -> a -> a -> Bool
okEqOrd a
x a
y a
z  =  a -> a -> a -> Bool
forall a. Eq a => a -> a -> a -> Bool
okEq  a
x a
y a
z
               Bool -> Bool -> Bool
&& a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
okOrd a
x a
y a
z
               Bool -> Bool -> Bool
&& (a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y) Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== (a
x a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
EQ) -- consistent instances

-- | Like 'okNum' but restricted to zero and positives.
--
-- > > check (okNumNonNegative :: Natural -> Natural -> Natural -> Bool)
-- > +++ OK, passed 200 tests.
okNumNonNegative :: (Eq a, Num a) => a -> a -> a -> Bool
okNumNonNegative :: a -> a -> a -> Bool
okNumNonNegative a
x a
y a
z  =  (a -> a -> a) -> a -> a -> Bool
forall b a. Eq b => (a -> a -> b) -> a -> a -> Bool
isCommutative a -> a -> a
forall a. Num a => a -> a -> a
(+) a
x a
y
                        Bool -> Bool -> Bool
&& (a -> a -> a) -> a -> a -> Bool
forall b a. Eq b => (a -> a -> b) -> a -> a -> Bool
isCommutative a -> a -> a
forall a. Num a => a -> a -> a
(*) a
x a
y
                        Bool -> Bool -> Bool
&& (a -> a -> a) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> a) -> a -> a -> a -> Bool
isAssociative a -> a -> a
forall a. Num a => a -> a -> a
(+) a
x a
y a
z
                        Bool -> Bool -> Bool
&& (a -> a -> a) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> a) -> a -> a -> a -> Bool
isAssociative a -> a -> a
forall a. Num a => a -> a -> a
(*) a
x a
y a
z
                        Bool -> Bool -> Bool
&& (a -> a -> a
forall a. Num a => a -> a -> a
(*) (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
forall a.
Eq a =>
(a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
`isDistributiveOver` a -> a -> a
forall a. Num a => a -> a -> a
(+)) a
x a
y a
z
                        Bool -> Bool -> Bool
&& (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdempotent (a -> a -> a
forall a. Num a => a -> a -> a
+a
0) a
x
                        Bool -> Bool -> Bool
&& (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdempotent (a -> a -> a
forall a. Num a => a -> a -> a
*a
1) a
x
                        Bool -> Bool -> Bool
&& (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdempotent a -> a
forall a. Num a => a -> a
abs a
x
                        Bool -> Bool -> Bool
&& (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdempotent a -> a
forall a. Num a => a -> a
signum a
x
                        Bool -> Bool -> Bool
&& a -> a
forall a. Num a => a -> a
abs a
x a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Num a => a -> a
signum a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x

-- | 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.0 Infinity
okNum :: (Eq a, Num a) => a -> a -> a -> Bool
okNum :: a -> a -> a -> Bool
okNum a
x a
y a
z  =  a -> a -> a -> Bool
forall a. (Eq a, Num a) => a -> a -> a -> Bool
okNumNonNegative a
x a
y a
z
             Bool -> Bool -> Bool
&& a -> a
forall a. Num a => a -> a
negate (a -> a
forall a. Num a => a -> a
negate a
x) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x
             Bool -> Bool -> Bool
&& a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0

-- | 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 b => a -> (a -> b) -> a -> Bool
(a
x =$ :: a -> (a -> b) -> a -> Bool
=$ a -> b
f) a
y  =  a -> b
f a
x b -> b -> Bool
forall a. Eq a => a -> a -> Bool
== a -> b
f a
y
infixl 4 =$

-- | See '=$'
($=) :: (a -> Bool) -> a -> Bool
$= :: (a -> Bool) -> a -> Bool
($=)  =  (a -> Bool) -> a -> Bool
forall a b. (a -> b) -> a -> b
($)
infixl 4 $=

-- | 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
(=|) :: Eq a => [a] -> Int -> [a] -> Bool
[a]
xs =| :: [a] -> Int -> [a] -> Bool
=| Int
n  =  [a]
xs [a] -> ([a] -> [a]) -> [a] -> Bool
forall b a. Eq b => a -> (a -> b) -> a -> Bool
=$ Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
n
infixl 4 =|

-- | See '=|'
(|=) :: (a -> Bool) -> a -> Bool
|= :: (a -> Bool) -> a -> Bool
(|=)  =  (a -> Bool) -> a -> Bool
forall a b. (a -> b) -> a -> b
($)
infixl 4 |=


-- | Deprecated: use 'isCommutative'.
{-# DEPRECATED commutative "Use isCommutative." #-}
commutative :: Eq b => (a -> a -> b) -> a -> a -> Bool
commutative :: (a -> a -> b) -> a -> a -> Bool
commutative  =  (a -> a -> b) -> a -> a -> Bool
forall b a. Eq b => (a -> a -> b) -> a -> a -> Bool
isCommutative

-- | Deprecated: use 'isAssociative'.
{-# DEPRECATED associative "Use isAssociative." #-}
associative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool
associative :: (a -> a -> a) -> a -> a -> a -> Bool
associative  =  (a -> a -> a) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> a) -> a -> a -> a -> Bool
isAssociative

-- | Deprecated: use 'isDistributiveOver'.
{-# DEPRECATED distributive "Use isDistributiveOver." #-}
distributive :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
distributive :: (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
distributive  =  (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
forall a.
Eq a =>
(a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
isDistributiveOver

-- | Deprecated: use 'isFlipped'.
{-# DEPRECATED symmetric2 "Use isFlipped." #-}
symmetric2 :: Eq c => (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
symmetric2 :: (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
symmetric2  =  (a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
forall c a b.
Eq c =>
(a -> b -> c) -> (b -> a -> c) -> a -> b -> Bool
isFlipped

-- | Deprecated: use 'isTransitive'.
{-# DEPRECATED transitive "Use isTransitive." #-}
transitive :: (a -> a -> Bool) -> a -> a -> a -> Bool
transitive :: (a -> a -> Bool) -> a -> a -> a -> Bool
transitive  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isTransitive

-- | Deprecated: use 'isReflexive'.
{-# DEPRECATED reflexive "Use isReflexive." #-}
reflexive :: (a -> a -> Bool) -> a -> Bool
reflexive :: (a -> a -> Bool) -> a -> Bool
reflexive  =  (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isReflexive

-- | Deprecated: use 'isIrreflexive'.
{-# DEPRECATED irreflexive "Use isIrreflexive." #-}
irreflexive :: (a -> a -> Bool) -> a -> Bool
irreflexive :: (a -> a -> Bool) -> a -> Bool
irreflexive  =  (a -> a -> Bool) -> a -> Bool
forall a. (a -> a -> Bool) -> a -> Bool
isIrreflexive

-- | Deprecated: use 'isSymmetric'.
{-# DEPRECATED symmetric "Use isSymmetric." #-}
symmetric :: (a -> a -> Bool) -> a -> a -> Bool
symmetric :: (a -> a -> Bool) -> a -> a -> Bool
symmetric  =  (a -> a -> Bool) -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> Bool
isSymmetric

-- | Deprecated: use 'isAntisymmetric'.
{-# DEPRECATED antisymmetric "Use isAntisymmetric." #-}
antisymmetric :: Eq a => (a -> a -> Bool) -> a -> a -> Bool
antisymmetric :: (a -> a -> Bool) -> a -> a -> Bool
antisymmetric  =  (a -> a -> Bool) -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> Bool
isAntisymmetric

-- | Deprecated: use 'isAsymmetric'.
{-# DEPRECATED asymmetric "Use isAsymmetric." #-}
asymmetric :: (a -> a -> Bool) -> a -> a -> Bool
asymmetric :: (a -> a -> Bool) -> a -> a -> Bool
asymmetric  =  (a -> a -> Bool) -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> Bool
isAsymmetric

-- | Deprecated: use 'isEquivalence'.
{-# DEPRECATED equivalence "Use isEquivalence." #-}
equivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool
equivalence :: (a -> a -> Bool) -> a -> a -> a -> Bool
equivalence  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isEquivalence

-- | Deprecated: use 'isPartialOrder'.
{-# DEPRECATED partialOrder "Use isPartialOrder." #-}
partialOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
partialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
partialOrder  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isPartialOrder

-- | Deprecated: use 'isStrictPartialOrder'.
{-# DEPRECATED strictPartialOrder "Use isStrictPartialOrder." #-}
strictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
strictPartialOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
strictPartialOrder  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. (a -> a -> Bool) -> a -> a -> a -> Bool
isStrictPartialOrder

-- | Deprecated: use 'isTotalOrder'.
{-# DEPRECATED totalOrder "Use isTotalOrder." #-}
totalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
totalOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
totalOrder  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isTotalOrder

-- | Deprecated: use 'isStrictTotalOrder'.
{-# DEPRECATED strictTotalOrder "Use isStrictTotalOrder." #-}
strictTotalOrder :: Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
strictTotalOrder :: (a -> a -> Bool) -> a -> a -> a -> Bool
strictTotalOrder  =  (a -> a -> Bool) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> Bool) -> a -> a -> a -> Bool
isStrictTotalOrder

-- | Deprecated: use 'isComparison'.
{-# DEPRECATED comparison "Use isComparison." #-}
comparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool
comparison :: (a -> a -> Ordering) -> a -> a -> a -> Bool
comparison  =  (a -> a -> Ordering) -> a -> a -> a -> Bool
forall a. (a -> a -> Ordering) -> a -> a -> a -> Bool
isComparison

-- | Deprecated: use 'isIdempotent'.
{-# DEPRECATED idempotent "Use isIdempotent." #-}
idempotent :: Eq a => (a -> a) -> a -> Bool
idempotent :: (a -> a) -> a -> Bool
idempotent  =  (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdempotent

-- | Deprecated: use 'isIdentity'.
{-# DEPRECATED identity "Use isIdentity." #-}
identity :: Eq a => (a -> a) -> a -> Bool
identity :: (a -> a) -> a -> Bool
identity  =  (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isIdentity

-- | Deprecated: use 'isNeverIdentity'.
{-# DEPRECATED neverIdentity "Use isNeverIdentity." #-}
neverIdentity :: Eq a => (a -> a) -> a -> Bool
neverIdentity :: (a -> a) -> a -> Bool
neverIdentity  =  (a -> a) -> a -> Bool
forall a. Eq a => (a -> a) -> a -> Bool
isNeverIdentity