{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
module Data.Functor.Contravariant.Coyoneda
  ( Coyoneda(..)
  , liftCoyoneda
  , lowerCoyoneda
  ) where
import Control.Arrow
import Data.Functor.Contravariant
import Data.Functor.Contravariant.Adjunction
import Data.Functor.Contravariant.Rep
data Coyoneda f a where
  Coyoneda :: (a -> b) -> f b -> Coyoneda f a
instance Contravariant (Coyoneda f) where
  contramap f (Coyoneda g m) = Coyoneda (g.f) m
  {-# INLINE contramap #-}
instance Representable f => Representable (Coyoneda f) where
  type Rep (Coyoneda f) = Rep f
  tabulate = liftCoyoneda . tabulate
  {-# INLINE tabulate #-}
  index (Coyoneda ab fb) a = index fb (ab a)
  {-# INLINE index #-}
  contramapWithRep beav (Coyoneda ac fc) = Coyoneda (left ac . beav) (contramapWithRep id fc)
  {-# INLINE contramapWithRep #-}
instance Adjunction f g => Adjunction (Coyoneda f) (Coyoneda g) where
  leftAdjunct f = liftCoyoneda . leftAdjunct (lowerCoyoneda . f)
  {-# INLINE leftAdjunct #-}
  rightAdjunct f = liftCoyoneda . rightAdjunct (lowerCoyoneda . f)
  {-# INLINE rightAdjunct #-}
liftCoyoneda :: f a -> Coyoneda f a
liftCoyoneda = Coyoneda id
{-# INLINE liftCoyoneda #-}
lowerCoyoneda :: Contravariant f => Coyoneda f a -> f a
lowerCoyoneda (Coyoneda f m) = contramap f m
{-# INLINE lowerCoyoneda #-}