-----------------------------------------------------------------------------
-- |
  Module       :   Data . Functor . 
  Copyright    :   ( C ) 2007 - 2011  
-- License     :  BSD-style (see the file LICENSE)
--
  Maintainer   :     <  >
-- Stability   :  provisional
-- Portability :  portable
--
  '  ' functors , sometimes referred to colloquially as @Cofunctor@ ,
-- even though the dual of a 'Functor' is just a 'Functor'. As with 'Functor'
  the definition of '  ' for a given ADT is unambiguous .
----------------------------------------------------------------------------

module Data.Functor.Contravariant ( 
  *  
    Contravariant(..)

   -- * Predicates 
   , Predicate ( .. ) 

   -- * Comparisons 
   , Comparison ( .. ) 
   ,   -- * Equivalence Relations 
   , Equivalence ( .. ) 
   , defaultEquivalence 
  
   -- * Dual arrows 
   , Op ( .. ) 
  
  -- * Predicates
  , Predicate(..)

  -- * Comparisons
  , Comparison(..)
  , defaultComparison

  -- * Equivalence Relations
  , Equivalence(..)
  , defaultEquivalence
  
  -- * Dual arrows
  , Op(..)
  -}
  ) where

import Control.Applicative

 import Data . Functor . Product 
 import Data . Functor . Constant 

import Data.Functor.Product
import Data.Functor.Constant
-}
-- | Any instance should be subject to the following laws:
--
  >  i d = i d
  >  f .   =  ( g . f )
--
  Note , that the second law follows from the free theorem of the type of
  '  ' and the first law , so you need only check that the former
-- condition holds.

class Contravariant f where
  contramap :: (a -> b) -> f b -> f a 



 newtype Predicate a = Predicate { getPredicate : : a - > Bool } 
 -- | A ' Predicate ' is a '  ' ' Functor ' , because '  ' can 
 -- apply its function argument to the input of the predicate . 
 instance   where 
   contramap f g = Predicate    . f 



 -- | Defines a total ordering on a type as per ' compare ' 
 newtype Comparison a = Comparison { getComparison : : a - > a - > Ordering } 

 -- | A ' Comparison ' is a '  ' ' Functor ' , because '  ' can 
 -- apply its function argument to each input to each input to the 
 -- comparison function . 
 instance   where 
   contramap f g = Comparison $ \a b - > getComparison g ( f a ) ( f b ) 

 -- | Compare using ' compare ' 
 defaultComparison : :  a = > Comparison a 
 defaultComparison = Comparison compare 



 -- | Define an equivalence relation 
 newtype Equivalence a = Equivalence { getEquivalence : : a - > a - > Bool } 
 -- | Equivalence relations are '  ' , because you can 
 -- apply the contramapped function to each input to the equivalence 
 -- relation . 
 instance   where 
   contramap f g = Equivalence $ \a b - > getEquivalence g ( f a ) ( f b ) 

 -- | Check for equivalence with ' = = ' 
 defaultEquivalence : : Eq a = > Equivalence a 
 defaultEquivalence = Equivalence (= =) 

 -- | Dual function arrows . 
 newtype Op a b = Op { getOp : : b - > a } 

 instance  ( Op a ) where 
   contramap f g = Op (   . f ) 

 -- | Data . Functor . Product 
 instance (   ,   ) = >  ( Product f g ) where 
   contramap f ( Pair a b ) = Pair (  f a ) ( contramap f b ) 

 -- | Data . Functor . Constant 
 instance  ( Constant a ) where 
   contramap _ (  a ) = Constant a 

 -- | Control . Applicative . Const 
 instance  ( Const a ) where 
   contramap _ ( Const a ) = Const a 

newtype Predicate a = Predicate { getPredicate :: a -> Bool } 
-- | A 'Predicate' is a 'Contravariant' 'Functor', because 'contramap' can 
-- apply its function argument to the input of the predicate.
instance Contravariant Predicate where
  contramap f g = Predicate $ getPredicate g . f



-- | Defines a total ordering on a type as per 'compare'
newtype Comparison a = Comparison { getComparison :: a -> a -> Ordering } 

-- | A 'Comparison' is a 'Contravariant' 'Functor', because 'contramap' can 
-- apply its function argument to each input to each input to the 
-- comparison function.
instance Contravariant Comparison where
  contramap f g = Comparison $ \a b -> getComparison g (f a) (f b)

-- | Compare using 'compare'
defaultComparison :: Ord a => Comparison a
defaultComparison = Comparison compare



-- | Define an equivalence relation 
newtype Equivalence a = Equivalence { getEquivalence :: a -> a -> Bool } 
-- | Equivalence relations are 'Contravariant', because you can 
-- apply the contramapped function to each input to the equivalence 
-- relation.
instance Contravariant Equivalence where
  contramap f g = Equivalence $ \a b -> getEquivalence g (f a) (f b)

-- | Check for equivalence with '=='
defaultEquivalence :: Eq a => Equivalence a
defaultEquivalence = Equivalence (==)

-- | Dual function arrows.
newtype Op a b = Op { getOp :: b -> a } 

instance Contravariant (Op a) where
  contramap f g = Op (getOp g . f)

-- | Data.Functor.Product
instance (Contravariant f, Contravariant g) => Contravariant (Product f g) where
  contramap f (Pair a b) = Pair (contramap f a) (contramap f b)

-- | Data.Functor.Constant
instance Contravariant (Constant a) where
  contramap _ (Constant a) = Constant a

-- | Control.Applicative.Const
instance Contravariant (Const a) where
  contramap _ (Const a) = Const a
-}
---------------------------------------------------------------------------
 |
 License     :  BSD-style (see the file LICENSE)

 Stability   :  provisional
 Portability :  portable

 even though the dual of a 'Functor' is just a 'Functor'. As with 'Functor'
--------------------------------------------------------------------------
 * Predicates 
 * Comparisons 
 * Equivalence Relations 
 * Dual arrows 
 * Predicates
 * Comparisons
 * Equivalence Relations
 * Dual arrows
 | Any instance should be subject to the following laws:


 condition holds.
 | A ' Predicate ' is a '  ' ' Functor ' , because '  ' can 
 apply its function argument to the input of the predicate . 
 | Defines a total ordering on a type as per ' compare ' 
 | A ' Comparison ' is a '  ' ' Functor ' , because '  ' can 
 apply its function argument to each input to each input to the 
 comparison function . 
 | Compare using ' compare ' 
 | Define an equivalence relation 
 | Equivalence relations are '  ' , because you can 
 apply the contramapped function to each input to the equivalence 
 relation . 
 | Check for equivalence with ' = = ' 
 | Dual function arrows . 
 | Data . Functor . Product 
 | Data . Functor . Constant 
 | Control . Applicative . Const 
 | A 'Predicate' is a 'Contravariant' 'Functor', because 'contramap' can 
 apply its function argument to the input of the predicate.
 | Defines a total ordering on a type as per 'compare'
 | A 'Comparison' is a 'Contravariant' 'Functor', because 'contramap' can 
 apply its function argument to each input to each input to the 
 comparison function.
 | Compare using 'compare'
 | Define an equivalence relation 
 | Equivalence relations are 'Contravariant', because you can 
 apply the contramapped function to each input to the equivalence 
 relation.
 | Check for equivalence with '=='
 | Dual function arrows.
 | Data.Functor.Product
 | Data.Functor.Constant
 | Control.Applicative.Const
  Module       :   Data . Functor . 
  Copyright    :   ( C ) 2007 - 2011  
  Maintainer   :     <  >
  '  ' functors , sometimes referred to colloquially as @Cofunctor@ ,
  the definition of '  ' for a given ADT is unambiguous .

module Data.Functor.Contravariant ( 
  *  
    Contravariant(..)

   , Predicate ( .. ) 

   , Comparison ( .. ) 
   , Equivalence ( .. ) 
   , defaultEquivalence 
  
   , Op ( .. ) 
  
  , Predicate(..)

  , Comparison(..)
  , defaultComparison

  , Equivalence(..)
  , defaultEquivalence
  
  , Op(..)
  -}
  ) where

import Control.Applicative

 import Data . Functor . Product 
 import Data . Functor . Constant 

import Data.Functor.Product
import Data.Functor.Constant
-}
  >  i d = i d
  >  f .   =  ( g . f )
  Note , that the second law follows from the free theorem of the type of
  '  ' and the first law , so you need only check that the former

class Contravariant f where
  contramap :: (a -> b) -> f b -> f a 



 newtype Predicate a = Predicate { getPredicate : : a - > Bool } 
 instance   where 
   contramap f g = Predicate    . f 



 newtype Comparison a = Comparison { getComparison : : a - > a - > Ordering } 

 instance   where 
   contramap f g = Comparison $ \a b - > getComparison g ( f a ) ( f b ) 

 defaultComparison : :  a = > Comparison a 
 defaultComparison = Comparison compare 



 newtype Equivalence a = Equivalence { getEquivalence : : a - > a - > Bool } 
 instance   where 
   contramap f g = Equivalence $ \a b - > getEquivalence g ( f a ) ( f b ) 

 defaultEquivalence : : Eq a = > Equivalence a 
 defaultEquivalence = Equivalence (= =) 

 newtype Op a b = Op { getOp : : b - > a } 

 instance  ( Op a ) where 
   contramap f g = Op (   . f ) 

 instance (   ,   ) = >  ( Product f g ) where 
   contramap f ( Pair a b ) = Pair (  f a ) ( contramap f b ) 

 instance  ( Constant a ) where 
   contramap _ (  a ) = Constant a 

 instance  ( Const a ) where 
   contramap _ ( Const a ) = Const a 

newtype Predicate a = Predicate { getPredicate :: a -> Bool } 
instance Contravariant Predicate where
  contramap f g = Predicate $ getPredicate g . f



newtype Comparison a = Comparison { getComparison :: a -> a -> Ordering } 

instance Contravariant Comparison where
  contramap f g = Comparison $ \a b -> getComparison g (f a) (f b)

defaultComparison :: Ord a => Comparison a
defaultComparison = Comparison compare



newtype Equivalence a = Equivalence { getEquivalence :: a -> a -> Bool } 
instance Contravariant Equivalence where
  contramap f g = Equivalence $ \a b -> getEquivalence g (f a) (f b)

defaultEquivalence :: Eq a => Equivalence a
defaultEquivalence = Equivalence (==)

newtype Op a b = Op { getOp :: b -> a } 

instance Contravariant (Op a) where
  contramap f g = Op (getOp g . f)

instance (Contravariant f, Contravariant g) => Contravariant (Product f g) where
  contramap f (Pair a b) = Pair (contramap f a) (contramap f b)

instance Contravariant (Constant a) where
  contramap _ (Constant a) = Constant a

instance Contravariant (Const a) where
  contramap _ (Const a) = Const a
-}