packages feed

monoidal-functors-0.3.0.0: src/Data/Bifunctor/BiInvariant.hs

module Data.Bifunctor.BiInvariant
  ( -- * BiInvariant
    BiInvariant (..),
    biinvIso,
    type Coercible1,
    type Coercible2,
  )
where

--------------------------------------------------------------------------------

import Control.Arrow (Arrow, Kleisli (Kleisli))
import Control.Category.Tensor (Iso (Iso))
import Control.Comonad (Cokleisli (Cokleisli))
import Data.Bifunctor (Bifunctor (bimap))
import Data.Bifunctor.Biap (Biap (Biap))
import Data.Bifunctor.Biff (Biff (Biff))
import Data.Bifunctor.Clown (Clown (Clown))
import Data.Bifunctor.Flip (Flip (Flip))
import Data.Bifunctor.Joker (Joker (Joker))
import Data.Bifunctor.Product (Product)
import Data.Bifunctor.Sum (Sum)
import Data.Bifunctor.Tannen (Tannen (Tannen))
import Data.Bifunctor.Wrapped (WrappedBifunctor (WrapBifunctor))
import Data.Coerce (Coercible)
import Data.Functor.Const (Const (Const))
import Data.Functor.Contravariant (Contravariant (contramap))
import Data.Kind (Constraint)
import Data.Profunctor (Costar (Costar), Forget (Forget), Profunctor (dimap), Star (Star), WrappedArrow (WrapArrow))
import Data.Profunctor.Cayley (Cayley (Cayley))
import Data.Profunctor.Choice (CopastroSum (CopastroSum), CotambaraSum, PastroSum, TambaraSum (TambaraSum))
import Data.Profunctor.Closed (Closure (Closure), Environment)
import Data.Profunctor.Composition (Procompose, Rift (Rift))
import Data.Profunctor.Mapping (CofreeMapping (CofreeMapping), FreeMapping)
import Data.Profunctor.Ran (Codensity (Codensity), Ran (Ran))
import Data.Profunctor.Strong (Copastro (Copastro), Cotambara, Pastro, Tambara (Tambara))
import Data.Profunctor.Traversing (CofreeTraversing (CofreeTraversing), FreeTraversing)
import Data.Profunctor.Yoneda (Coyoneda, Yoneda (Yoneda))
import Data.Semigroup (Arg)
import Data.Tagged (Tagged (Tagged))
import Data.These (These)
import GHC.Generics (K1)
import Prelude

--------------------------------------------------------------------------------

-- $setup
-- >>> :set -dppr-cols=1000
-- >>> import Prelude
-- >>> import Control.Category.Tensor (Iso (..), fwd)

--------------------------------------------------------------------------------

-- | A bifunctor is 'BiInvariant' if it is parametric in both its type
-- parameters.
--
-- === Laws
--
-- @
-- 'biinvmap' 'id' 'id' 'id' 'id' ≡ 'id'
-- 'biinvmap' @g2@ @g2'@ @f2@ @f2'@ 'Control.Category..' 'Data.Functor.Invariant.invmap' @g1@ @g1'@ @f1@ @f1'@ ≡ 'Data.Functor.Invariant.invmap' (@g2@ 'Control.Category..' @g1@) (@g1'@ 'Control.Category..' @g2'@) (@f2@ 'Control.Category..' @f1@) (@f1'@ 'Control.Category..' @f2'@)
-- @
class BiInvariant p where
  -- | Used to apply a pair of isomorphic functions to @p a b@.
  -- 'Biinvmap' picks out the appropriate half of the iso depending if
  -- @p@ is covariant or contravariant on each parameter.
  --
  -- ==== __Examples__
  --
  -- >>> :t biinvmap @(,) (read @Int) show (read @Bool) show
  -- biinvmap @(,) (read @Int) show (read @Bool) show :: (Int, Bool) -> (String, String)
  --
  -- >>> biinvmap @(,) (read @Int) show (read @Bool) show (10, True)
  -- ("10","True")
  --
  -- >>> :t biinvmap @(->) (read @Int) show (read @Bool) show
  -- biinvmap @(->) (read @Int) show (read @Bool) show :: (Int -> Bool) -> String -> String
  --
  -- >>> biinvmap @(->) (read @Int) show (read @Bool) show (\i -> i > 10) "12"
  -- "True"
  biinvmap :: (a' -> a) -> (a -> a') -> (b' -> b) -> (b -> b') -> p a b -> p a' b'

-- | BiInvariant witnesses an Isomorphism
--
-- ==== __Examples__
--
-- >>> fwd (biinvIso @(,) (Iso (read @Int) show) (Iso (read @Bool) show)) ("10", "True")
-- (10,True)
biinvIso :: (BiInvariant p) => Iso (->) a a' -> Iso (->) b b' -> Iso (->) (p a b) (p a' b')
biinvIso (Iso f f') (Iso g g') = Iso (biinvmap f' f g' g) (biinvmap f f' g g')

-- | Boilerplate newtype to derive 'BiInvariant' for any 'Profunctor'.
newtype FromProfunctor p a b = FromProfunctor {runPro :: p a b}

instance (Profunctor p) => BiInvariant (FromProfunctor p) where
  biinvmap :: (a' -> a) -> (a -> a') -> (b' -> b) -> (b -> b') -> FromProfunctor p a b -> FromProfunctor p a' b'
  biinvmap f _ _ g = FromProfunctor . dimap f g . runPro

-- | Boilerplate newtype to derive 'BiInvariant' for any 'Bifunctor'.
newtype FromBifunctor p a b = FromBifunctor {runBi :: p a b}

instance (Bifunctor p) => BiInvariant (FromBifunctor p) where
  biinvmap :: (a' -> a) -> (a -> a') -> (b' -> b) -> (b -> b') -> FromBifunctor p a b -> FromBifunctor p a' b'
  biinvmap _ f _ g = FromBifunctor . bimap f g . runBi

-- | Boilerplate newtype to derive 'BiInvariant' for any 'Contravariant'.
newtype FromContra f a = FromContra {runContra :: f a}

instance (Contravariant f) => Contravariant (FromContra f) where
  contramap :: (Contravariant f) => (a' -> a) -> FromContra f a -> FromContra f a'
  contramap f = FromContra . contramap f . runContra

newtype FromFunctor f a = FromFunctor (f a)
  deriving (Functor)

type Coercible1 f = ((forall a b. (Coercible a b) => Coercible (f a) (f b)) :: Constraint)

type Coercible2 f = (forall a b c d. (Coercible a b, Coercible c d) => Coercible (f a c) (f b d) :: Constraint)

deriving via (FromProfunctor (->)) instance BiInvariant (->)

deriving via (FromProfunctor (Biff p f g)) instance (Profunctor p, Functor f, Functor g) => BiInvariant (Biff (FromProfunctor p) f g)

deriving via (FromProfunctor (Cayley f q)) instance (Functor f, Profunctor q) => BiInvariant (Cayley f q)

deriving via (FromProfunctor (Closure p)) instance (Profunctor p) => BiInvariant (Closure p)

deriving via (FromProfunctor (Clown f :: * -> * -> *)) instance (Contravariant f) => BiInvariant (Clown (FromContra f) :: * -> * -> *)

deriving via (FromProfunctor (Codensity p)) instance (Profunctor p) => BiInvariant (Codensity p)

deriving via (FromProfunctor (CofreeMapping p)) instance (Profunctor p) => BiInvariant (CofreeMapping p)

deriving via (FromProfunctor (CofreeTraversing p)) instance (Profunctor p) => BiInvariant (CofreeTraversing p)

deriving via (FromProfunctor (Cokleisli w)) instance (Functor w) => BiInvariant (Cokleisli w)

deriving via (FromProfunctor (Copastro p)) instance BiInvariant (Copastro p)

deriving via (FromProfunctor (CopastroSum p)) instance BiInvariant (CopastroSum p)

deriving via (FromProfunctor (Costar f)) instance (Functor f) => BiInvariant (Costar f)

deriving via (FromProfunctor (Cotambara p)) instance BiInvariant (Cotambara p)

deriving via (FromProfunctor (CotambaraSum p)) instance BiInvariant (CotambaraSum p)

deriving via (FromProfunctor (Coyoneda p)) instance BiInvariant (Coyoneda p)

deriving via (FromProfunctor (Environment p)) instance BiInvariant (Environment p)

deriving via (FromProfunctor (Forget r :: * -> * -> *)) instance BiInvariant (Forget r :: * -> * -> *)

deriving via (FromProfunctor (FreeMapping p)) instance BiInvariant (FreeMapping p)

deriving via (FromProfunctor (FreeTraversing p)) instance BiInvariant (FreeTraversing p)

deriving via (FromProfunctor (Joker f :: * -> * -> *)) instance (Functor f) => BiInvariant (Joker (FromContra f) :: * -> * -> *)

deriving via (FromProfunctor (Kleisli m)) instance (Monad m) => BiInvariant (Kleisli m)

deriving via (FromProfunctor (Pastro p)) instance BiInvariant (Pastro p)

deriving via (FromProfunctor (PastroSum p)) instance BiInvariant (PastroSum p)

deriving via (FromProfunctor (Procompose p q)) instance (Profunctor p, Profunctor q) => BiInvariant (Procompose p q)

deriving via (FromProfunctor (Product p q)) instance (Profunctor p, Profunctor q) => BiInvariant (Product (FromProfunctor p) (FromProfunctor q))

deriving via (FromProfunctor (Ran p q)) instance (Profunctor p, Profunctor q) => BiInvariant (Ran p q)

deriving via (FromProfunctor (Rift p q)) instance (Profunctor p, Profunctor q) => BiInvariant (Rift p q)

deriving via (FromProfunctor (Star f)) instance (Functor f) => BiInvariant (Star (FromFunctor f))

deriving via (FromProfunctor (Star f)) instance (Functor f) => BiInvariant (Star (FromContra f))

deriving via (FromProfunctor (Sum p q)) instance (Profunctor p, Profunctor q) => BiInvariant (Sum (FromProfunctor p) (FromProfunctor q))

deriving via (FromProfunctor (Tagged :: * -> * -> *)) instance BiInvariant (Tagged :: * -> * -> *)

deriving via (FromProfunctor (Tambara p)) instance (Profunctor p) => BiInvariant (Tambara p)

deriving via (FromProfunctor (TambaraSum p)) instance (Profunctor p) => BiInvariant (TambaraSum p)

deriving via (FromProfunctor (Tannen f q)) instance (Functor f, Profunctor q) => BiInvariant (Tannen f q)

deriving via (FromProfunctor (WrappedArrow p)) instance (Arrow p) => BiInvariant (WrappedArrow p)

deriving via (FromProfunctor (Yoneda p)) instance BiInvariant (Yoneda p)

deriving via (FromBifunctor ((,,) x1)) instance BiInvariant ((,,) x1)

deriving via (FromBifunctor ((,,,) x1 x2)) instance BiInvariant ((,,,) x1 x2)

deriving via (FromBifunctor ((,,,,) x1 x2 x3)) instance BiInvariant ((,,,,) x1 x2 x3)

deriving via (FromBifunctor ((,,,,,) x1 x2 x3 x4)) instance BiInvariant ((,,,,,) x1 x2 x3 x4)

deriving via (FromBifunctor ((,,,,,,) x1 x2 x3 x4 x5)) instance BiInvariant ((,,,,,,) x1 x2 x3 x4 x5)

deriving via (FromBifunctor (,)) instance BiInvariant (,)

deriving via (FromBifunctor Arg) instance BiInvariant Arg

deriving via (FromBifunctor (Biap bi)) instance (Bifunctor bi) => BiInvariant (Biap bi)

deriving via (FromBifunctor (Biff p f g)) instance (Bifunctor p, Functor f, Functor g) => BiInvariant (Biff (FromBifunctor p) f g)

deriving via (FromBifunctor (Clown f :: * -> * -> *)) instance (Functor f) => BiInvariant (Clown (FromFunctor f) :: * -> * -> *)

deriving via (FromBifunctor (Const :: * -> * -> *)) instance BiInvariant (Const :: * -> * -> *)

deriving via (FromBifunctor Either) instance BiInvariant Either

deriving via (FromBifunctor (Flip p)) instance (Bifunctor p) => BiInvariant (Flip p)

deriving via (FromBifunctor (Joker f :: * -> * -> *)) instance (Functor f) => BiInvariant (Joker (FromFunctor f) :: * -> * -> *)

deriving via (FromBifunctor (K1 i :: * -> * -> *)) instance BiInvariant (K1 i :: * -> * -> *)

deriving via (FromBifunctor (Product p q)) instance (Bifunctor p, Bifunctor q) => BiInvariant (Product (FromBifunctor p) (FromBifunctor q))

deriving via (FromBifunctor (Sum p q)) instance (Bifunctor p, Bifunctor q) => BiInvariant (Sum (FromBifunctor p) (FromBifunctor q))

deriving via (FromBifunctor (Tannen f q)) instance (Functor f, Coercible1 f, Bifunctor q) => BiInvariant (Tannen (FromFunctor f) (FromBifunctor q))

deriving via (FromBifunctor These) instance BiInvariant These

deriving via (FromBifunctor (WrappedBifunctor p)) instance (Bifunctor p) => BiInvariant (WrappedBifunctor p)