------------------------------------------------------------------------
-- The Agda standard library
--
-- Sum combinators for propositional equality preserving functions
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

module Data.Sum.Function.Propositional where

open import Data.Sum.Base using (_⊎_)
open import Data.Sum.Function.Setoid
open import Data.Sum.Relation.Binary.Pointwise using (Pointwise-≡↔≡; _⊎ₛ_)
open import Function.Construct.Composition as Compose
open import Function.Related.Propositional
  using (_∼[_]_; implication; reverseImplication; equivalence; injection;
    reverseInjection; leftInverse; surjection; bijection)
open import Function.Base using (id)
open import Function.Bundles
  using (Inverse; _⟶_; _⇔_; _↣_; _↠_; _↩_; _↪_; _⤖_; _↔_)
open import Function.Properties.Inverse as Inv
open import Level using (Level; _⊔_)
open import Relation.Binary.Core using (REL)
open import Relation.Binary.Bundles using (Setoid)
open import Relation.Binary.PropositionalEquality.Properties using (setoid)

private
  variable
    a b c d : Level
    A B C D : Set a


------------------------------------------------------------------------
-- Helper lemma

private
  liftViaInverse : {R :  {a b ℓ₁ ℓ₂}  REL (Setoid a ℓ₁) (Setoid b ℓ₂) (a  b  ℓ₁  ℓ₂)} 
                   (∀ {a b c ℓ₁ ℓ₂ ℓ₃} {S : Setoid a ℓ₁} {T : Setoid b ℓ₂} {U : Setoid c ℓ₃}  R S T  R T U  R S U) 
                   (∀ {a b ℓ₁ ℓ₂} {S : Setoid a ℓ₁} {T : Setoid b ℓ₂}  Inverse S T  R S T) 
                   (R (setoid A) (setoid C)  R (setoid B) (setoid D)  R (setoid A ⊎ₛ setoid B) (setoid C ⊎ₛ setoid D)) 
                   R (setoid A) (setoid C)  R (setoid B) (setoid D) 
                   R (setoid (A  B)) (setoid (C  D))
  liftViaInverse trans inv⇒R lift RAC RBD =
    Inv.transportVia trans inv⇒R (Inv.sym (Pointwise-≡↔≡ _ _)) (lift RAC RBD) (Pointwise-≡↔≡ _ _)

------------------------------------------------------------------------
-- Combinators for various function types

infixr 1 _⊎-⟶_ _⊎-⇔_ _⊎-↣_ _⊎-↩_ _⊎-↪_ _⊎-↔_

_⊎-⟶_ : A  B  C  D  (A  C)  (B  D)
_⊎-⟶_ = liftViaInverse Compose.function Inv.toFunction _⊎-function_


_⊎-⇔_ : A  B  C  D  (A  C)  (B  D)
_⊎-⇔_ = liftViaInverse Compose.equivalence Inverse⇒Equivalence _⊎-equivalence_

_⊎-↣_ : A  B  C  D  (A  C)  (B  D)
_⊎-↣_ = liftViaInverse Compose.injection Inverse⇒Injection _⊎-injection_

_⊎-↠_ : A  B  C  D  (A  C)  (B  D)
_⊎-↠_ = liftViaInverse Compose.surjection Inverse⇒Surjection _⊎-surjection_

_⊎-↩_ : A  B  C  D  (A  C)  (B  D)
_⊎-↩_ = liftViaInverse Compose.leftInverse Inverse.leftInverse _⊎-leftInverse_

_⊎-↪_ : A  B  C  D  (A  C)  (B  D)
_⊎-↪_ = liftViaInverse Compose.rightInverse Inverse.rightInverse _⊎-rightInverse_

_⊎-⤖_ : A  B  C  D  (A  C)  (B  D)
_⊎-⤖_ = liftViaInverse Compose.bijection Inverse⇒Bijection _⊎-bijection_

_⊎-↔_ : A  B  C  D  (A  C)  (B  D)
_⊎-↔_ = liftViaInverse Compose.inverse id _⊎-inverse_

infixr 1 _⊎-cong_

_⊎-cong_ :  {k}  A ∼[ k ] B  C ∼[ k ] D  (A  C) ∼[ k ] (B  D)
_⊎-cong_ {k = implication}         = _⊎-⟶_
_⊎-cong_ {k = reverseImplication}  = _⊎-⟶_
_⊎-cong_ {k = equivalence}         = _⊎-⇔_
_⊎-cong_ {k = injection}           = _⊎-↣_
_⊎-cong_ {k = reverseInjection}    = _⊎-↣_
_⊎-cong_ {k = leftInverse}         = _⊎-↪_
_⊎-cong_ {k = surjection}          = _⊎-↠_
_⊎-cong_ {k = bijection}           = _⊎-↔_