----------------------------------------------------------------------------------------------------
-- The "if-and-only-if" relation
----------------------------------------------------------------------------------------------------

{-# OPTIONS --cubical --safe --guardedness --erasure #-}

module Iff where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels

open import Cubical.Data.Sigma

open import PropTrunc

private
 variable
  ℓ₁ ℓ₂ ℓ₃ : Level

_↔_ : (A : Type ℓ₁) (B : Type ℓ₂)  Type _
A  B = (A  B) × (B  A)

infix   1 _↔_

lr : {A : Type ℓ₁}{B : Type ℓ₂}  A  B  A  B
lr = fst

rl : {A : Type ℓ₁}{B : Type ℓ₂}  A  B  B  A
rl = snd

isProp↔ : {A : Type ℓ₁}{B : Type ℓ₂}
         isProp A  isProp B  isProp (A  B)
isProp↔ pA pB = isProp× (isPropΠ  _  pB)) (isPropΠ  _  pA))

↔-refl : {A : Type ℓ₁}  A  A
↔-refl =  a  a) ,  a  a)

↔-sym : {A : Type ℓ₁}{B : Type ℓ₂}  A  B  B  A
↔-sym (l , r) = (r , l)

↔-trans : {A : Type ℓ₁}{B : Type ℓ₂}{C : Type ℓ₃}
         (A  B)  (B  C)  (A  C)
↔-trans A↔B B↔C = (lr B↔C  lr A↔B) , (rl A↔B  rl B↔C)

_↔⟨_⟩_ : (A : Type ℓ₁) {B : Type ℓ₂} {C : Type ℓ₃}
          (A  B)  (B  C)  (A  C)
A ↔⟨ A↔B  B↔C = ↔-trans A↔B B↔C

_↔∎ : (A : Type ℓ₁)  A  A
A ↔∎ = ↔-refl

infixr  0 _↔⟨_⟩_
infix   1 _↔∎

∥-∥↔ : {A : Type ℓ₁}{B : Type ℓ₂}  A  B   A    B 
∥-∥↔ p = ∥-∥map (lr p) , ∥-∥map (rl p)