{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}

#if HAVE_QUANTIFIED_CONSTRAINTS
{-# LANGUAGE QuantifiedConstraints #-}
#endif

{-# OPTIONS_GHC -Wall #-}

module Test.QuickCheck.Classes.Bifunctor
  (
#if HAVE_BINARY_LAWS
    bifunctorLaws
#endif
  ) where

import Data.Bifunctor(Bifunctor(..))
import Test.QuickCheck hiding ((.&.))
#if HAVE_BINARY_LAWS
import Data.Functor.Classes (Eq2,Show2)
#endif
import Test.QuickCheck.Property (Property)

import Test.QuickCheck.Classes.Internal

#if HAVE_BINARY_LAWS

-- | Tests the following 'Bifunctor' properties:
--
-- [/Identity/]
--   @'bimap' 'id' 'id' ≡ 'id'@
-- [/First Identity/]
--   @'first' 'id' ≡ 'id'@
-- [/Second Identity/] 
--   @'second' 'id' ≡ 'id'@
-- [/Bifunctor Composition/]
--   @'bimap' f g ≡ 'first' f '.' 'second' g@ 
--
-- /Note/: This property test is only available when this package is built with
-- @base-4.9+@ or @transformers-0.5+@.
bifunctorLaws :: forall proxy f.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b), forall a b. (Show a, Show b) => Show (f a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b))
#else
  (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f)
#endif
  => proxy f -> Laws
bifunctorLaws :: proxy f -> Laws
bifunctorLaws proxy f
p = String -> [(String, Property)] -> Laws
Laws String
"Bifunctor"
  [ (String
"Identity", proxy f -> Property
forall (proxy :: (* -> * -> *) -> *) (f :: * -> * -> *).
(Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b),
 forall a b. (Show a, Show b) => Show (f a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b)) =>
proxy f -> Property
bifunctorIdentity proxy f
p)
  , (String
"First Identity", proxy f -> Property
forall (proxy :: (* -> * -> *) -> *) (f :: * -> * -> *).
(Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b),
 forall a b. (Show a, Show b) => Show (f a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b)) =>
proxy f -> Property
bifunctorFirstIdentity proxy f
p)
  , (String
"Second Identity", proxy f -> Property
forall (proxy :: (* -> * -> *) -> *) (f :: * -> * -> *).
(Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b),
 forall a b. (Show a, Show b) => Show (f a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b)) =>
proxy f -> Property
bifunctorSecondIdentity proxy f
p)
  , (String
"Bifunctor Composition", proxy f -> Property
forall (proxy :: (* -> * -> *) -> *) (f :: * -> * -> *).
(Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b),
 forall a b. (Show a, Show b) => Show (f a b),
 forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b)) =>
proxy f -> Property
bifunctorComposition proxy f
p)
  ]

bifunctorIdentity :: forall proxy f.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b), forall a b. (Show a, Show b) => Show (f a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b))
#else
  (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f)
#endif
  => proxy f -> Property
bifunctorIdentity :: proxy f -> Property
bifunctorIdentity proxy f
_ = (Apply2 f Integer Integer -> Bool) -> Property
forall prop. Testable prop => prop -> Property
property ((Apply2 f Integer Integer -> Bool) -> Property)
-> (Apply2 f Integer Integer -> Bool) -> Property
forall a b. (a -> b) -> a -> b
$ \(Apply2 (f Integer Integer
x :: f Integer Integer)) -> f Integer Integer -> f Integer Integer -> Bool
forall b (f :: * -> * -> *) a.
(forall a1. (Eq a1, Eq b) => Eq (f a1 b), Eq a, Eq b) =>
f a b -> f a b -> Bool
eq2 ((Integer -> Integer)
-> (Integer -> Integer) -> f Integer Integer -> f Integer Integer
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Integer -> Integer
forall a. a -> a
id Integer -> Integer
forall a. a -> a
id f Integer Integer
x) f Integer Integer
x

bifunctorFirstIdentity :: forall proxy f.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b), forall a b. (Show a, Show b) => Show (f a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b))
#else
  (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f)
#endif
  => proxy f -> Property
bifunctorFirstIdentity :: proxy f -> Property
bifunctorFirstIdentity proxy f
_ = (Apply2 f Integer Integer -> Bool) -> Property
forall prop. Testable prop => prop -> Property
property ((Apply2 f Integer Integer -> Bool) -> Property)
-> (Apply2 f Integer Integer -> Bool) -> Property
forall a b. (a -> b) -> a -> b
$ \(Apply2 (f Integer Integer
x :: f Integer Integer)) -> f Integer Integer -> f Integer Integer -> Bool
forall b (f :: * -> * -> *) a.
(forall a1. (Eq a1, Eq b) => Eq (f a1 b), Eq a, Eq b) =>
f a b -> f a b -> Bool
eq2 ((Integer -> Integer) -> f Integer Integer -> f Integer Integer
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Integer -> Integer
forall a. a -> a
id f Integer Integer
x) f Integer Integer
x

bifunctorSecondIdentity :: forall proxy f.
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b), forall a b. (Show a, Show b) => Show (f a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b))
#else
  (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f)
#endif
  => proxy f -> Property
bifunctorSecondIdentity :: proxy f -> Property
bifunctorSecondIdentity proxy f
_ = (Apply2 f Integer Integer -> Bool) -> Property
forall prop. Testable prop => prop -> Property
property ((Apply2 f Integer Integer -> Bool) -> Property)
-> (Apply2 f Integer Integer -> Bool) -> Property
forall a b. (a -> b) -> a -> b
$ \(Apply2 (f Integer Integer
x :: f Integer Integer)) -> f Integer Integer -> f Integer Integer -> Bool
forall b (f :: * -> * -> *) a.
(forall a1. (Eq a1, Eq b) => Eq (f a1 b), Eq a, Eq b) =>
f a b -> f a b -> Bool
eq2 ((Integer -> Integer) -> f Integer Integer -> f Integer Integer
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Integer -> Integer
forall a. a -> a
id f Integer Integer
x) f Integer Integer
x

bifunctorComposition :: forall proxy f. 
#if HAVE_QUANTIFIED_CONSTRAINTS
  (Bifunctor f, forall a b. (Eq a, Eq b) => Eq (f a b), forall a b. (Show a, Show b) => Show (f a b), forall a b. (Arbitrary a, Arbitrary b) => Arbitrary (f a b))
#else
  (Bifunctor f, Eq2 f, Show2 f, Arbitrary2 f)
#endif
  => proxy f -> Property
bifunctorComposition :: proxy f -> Property
bifunctorComposition proxy f
_ = (Apply2 f Integer Integer -> Bool) -> Property
forall prop. Testable prop => prop -> Property
property ((Apply2 f Integer Integer -> Bool) -> Property)
-> (Apply2 f Integer Integer -> Bool) -> Property
forall a b. (a -> b) -> a -> b
$ \(Apply2 (f Integer Integer
z :: f Integer Integer)) -> f Integer Integer -> f Integer Integer -> Bool
forall b (f :: * -> * -> *) a.
(forall a1. (Eq a1, Eq b) => Eq (f a1 b), Eq a, Eq b) =>
f a b -> f a b -> Bool
eq2 ((Integer -> Integer)
-> (Integer -> Integer) -> f Integer Integer -> f Integer Integer
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Integer -> Integer
forall a. a -> a
id Integer -> Integer
forall a. a -> a
id f Integer Integer
z) (((Integer -> Integer) -> f Integer Integer -> f Integer Integer
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Integer -> Integer
forall a. a -> a
id (f Integer Integer -> f Integer Integer)
-> (f Integer Integer -> f Integer Integer)
-> f Integer Integer
-> f Integer Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Integer) -> f Integer Integer -> f Integer Integer
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Integer -> Integer
forall a. a -> a
id) f Integer Integer
z)

#endif