    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    module Test.Validity.Relations.Symmetry
      ( symmetricOnElems,
        symmetryOnGens,
        symmetry,
        symmetryOnArbitrary,
      )
    where

    import Data.GenValidity
    import Test.QuickCheck
    import Test.Validity.Property.Utils

    -- |
    --
    -- \[
    --   Symmetric(\prec)
    --   \quad\equiv\quad
    --   \forall a, b: (a \prec b) \Leftrightarrow (b \prec a)
    -- \]
    symmetricOnElems ::
      -- | A relation
      (a -> a -> Bool) ->
      a ->
      -- | Two elements
      a ->
      Bool
    symmetricOnElems :: forall a. (a -> a -> Bool) -> a -> a -> Bool
    symmetricOnElems a -> a -> Bool
    func a
    a a
    b = a -> a -> Bool
    func a
    a a
    b Bool -> Bool -> Bool
    <==> a -> a -> Bool
    func a
    b a
    a

    symmetryOnGens ::
      Show a => (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
    symmetryOnGens :: forall a.
    Show a =>
    (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
    symmetryOnGens a -> a -> Bool
    func Gen (a, a)
    gen a -> [a]
    s =
      Gen (a, a) -> ((a, a) -> [(a, a)]) -> ((a, a) -> Bool) -> Property
    forall a prop.
    (Show a, Testable prop) =>
    Gen a -> (a -> [a]) -> (a -> prop) -> Property
    forAllShrink Gen (a, a)
    gen ((a -> [a]) -> (a, a) -> [(a, a)]
    forall a. (a -> [a]) -> (a, a) -> [(a, a)]
    shrinkT2 a -> [a]
    s) (((a, a) -> Bool) -> Property) -> ((a, a) -> Bool) -> Property
    forall a b. (a -> b) -> a -> b
    $ (a -> a -> Bool) -> (a, a) -> Bool
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry ((a -> a -> Bool) -> (a, a) -> Bool)
    -> (a -> a -> Bool) -> (a, a) -> Bool
    forall a b. (a -> b) -> a -> b
    $ (a -> a -> Bool) -> a -> a -> Bool
    forall a. (a -> a -> Bool) -> a -> a -> Bool
    symmetricOnElems a -> a -> Bool
    func

    -- |
    --
    -- prop> symmetry ((==) :: Int -> Int -> Bool)
    -- prop> symmetry ((/=) :: Int -> Int -> Bool)
    symmetry :: (Show a, GenValid a) => (a -> a -> Bool) -> Property
    symmetry :: forall a. (Show a, GenValid a) => (a -> a -> Bool) -> Property
    symmetry a -> a -> Bool
    func = (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
    forall a.
    Show a =>
    (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
    symmetryOnGens a -> a -> Bool
    func Gen (a, a)
    forall a. GenValid a => Gen a
    genValid a -> [a]
    forall a. GenValid a => a -> [a]
    shrinkValid

    -- |
    --
    -- prop> symmetryOnArbitrary ((==) :: Int -> Int -> Bool)
    -- prop> symmetryOnArbitrary ((/=) :: Int -> Int -> Bool)
    symmetryOnArbitrary :: (Show a, Arbitrary a) => (a -> a -> Bool) -> Property
    symmetryOnArbitrary :: forall a. (Show a, Arbitrary a) => (a -> a -> Bool) -> Property
    symmetryOnArbitrary a -> a -> Bool
    func = (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
    forall a.
    Show a =>
    (a -> a -> Bool) -> Gen (a, a) -> (a -> [a]) -> Property
    symmetryOnGens a -> a -> Bool
    func Gen (a, a)
    forall a. Arbitrary a => Gen a
    arbitrary a -> [a]
    forall a. Arbitrary a => a -> [a]
    shrink