{-# OPTIONS --without-K #-}
module function.extensionality.nondep where
open import sum
open import equality.core
open import equality.calculus
open import equality.reasoning
open import function.core using (id; _∘_)
open import function.isomorphism.core
open import function.isomorphism.coherent
open import hott.hlevel.core
open import hott.weak-equivalence.core
open import hott.univalence
open import function.extensionality.core
private
  
  
  module Paths {i} (X : Set i) where
    
    
    
    Δ : Set _
    Δ = Σ X λ x₁
      → Σ X λ x₂
      → x₁ ≡ x₂
    
    π₁ : Δ → X
    π₁ = proj₁
    π₂ : Δ → X
    π₂ = proj₁ ∘ proj₂
    
    δ : X → Δ
    δ x = (x , x , refl)
    
    δ-we : weak-equiv δ
    δ-we (x , .x , refl) = (x , refl)
                         , (λ { (x' , p) → lem _ x' p })
      where
        K : (d : Δ) → δ (π₁ d) ≡ d
        K (x , .x , refl) = refl
        lem : (d : Δ)(x : X)(p : δ x ≡ d)
            → _≡_ {A = δ ⁻¹ d} (π₁ d , K d) (x , p)
        lem .(x , x , refl) x refl = refl
    Δ-equiv : X ≈ Δ
    Δ-equiv = δ , δ-we
  
  
  
  module Lift {i} j (A : Set i) where
    
    lift : {X Y : Set j}
         → (X → Y) → (A → X) → (A → Y)
    lift f g a = f (g a)
    
    lift≡ : {X Y : Set j}
            → X ≡ Y → (A → X) ≡ (A → Y)
    lift≡ refl = refl
    
    lift-coherence : {X Y : Set j}(p : X ≡ Y)
                   → coerce (lift≡ p)
                   ≡ lift (coerce p)
    lift-coherence refl = refl
    
    
    
    
    lift≈ : {X Y : Set j}
          → X ≈ Y
          → (A → X) ≈ (A → Y)
    lift≈ = ≡⇒≈ ∘ lift≡ ∘ ≈⇒≡
    
    lift≈-coherence : {X Y : Set j}
                    → (f : X ≈ Y)
                    → apply≈ (lift≈ f) ≡ lift (apply≈ f)
    lift≈-coherence f = begin
        proj₁ (lift≈ f)
      ≡⟨ refl ⟩
        coerce (lift≡ (≈⇒≡ f))
      ≡⟨ lift-coherence (≈⇒≡ f) ⟩
        lift (coerce (≈⇒≡ f))
      ≡⟨ cong lift (uni-coherence f) ⟩
        lift (proj₁ f)
      ∎
      where open ≡-Reasoning
    
    lift≈-inverse : {X Y : Set j}
                  → (f : X ≈ Y)
                  → (g : Y → X)
                  → g ∘ apply≈ f ≡ id
                  → (u : A → Y)
                  → lift g u ≡ invert≈ (lift≈ f) u
    lift≈-inverse f g p u = begin
        lift g u
      ≡⟨ cong (lift g) (sym (iso₂ u)) ⟩
        lift g (to (from u))
      ≡⟨ cong (λ z → lift g (z (from u)))
              (lift≈-coherence f) ⟩
        lift g (lift (apply≈ f) (from u))
      ≡⟨ refl ⟩
        lift (g ∘ apply≈ f) (from u)
      ≡⟨ cong (λ z → lift z (from u)) p ⟩
        from u
      ≡⟨ refl ⟩
        invert≈ (lift≈ f) u
      ∎
      where
        open ≡-Reasoning
        open _≅_ (≈⇒≅ (lift≈ f))
abstract
  ext₀ : ∀ {i j} → Extensionality i j
  ext₀ {i}{j} {X} {Y} {f} {g} h = main
    where
      
      open Paths Y renaming (Δ to Y')
      open Lift j X
      
      
      iso' : (X → Y) ≅ (X → Y')
      iso' = ≈⇒≅ (lift≈ Δ-equiv)
      
      
      
      
      
      lem : (k : X → Y') → δ ∘ π₁ ∘ k ≡ k
      lem k = begin
          δ ∘ π₁ ∘ k
        ≡⟨ cong (λ t → t (π₁ ∘ k))
                 (sym (lift≈-coherence Δ-equiv)) ⟩
          to (π₁ ∘ k)
        ≡⟨ cong to (lift≈-inverse Δ-equiv π₁ refl k) ⟩
          to (from k)
        ≡⟨ iso₂ k ⟩
          k
        ∎
        where
          open ≡-Reasoning
          open _≅_ iso'
      
      
      
      
      
      main : f ≡ g
      main = begin
          f
        ≡⟨ refl ⟩
          π₁ ∘ k
        ≡⟨ refl ⟩
          π₂ ∘ δ ∘ π₁ ∘ k
        ≡⟨ cong (_∘_ π₂) (lem k) ⟩
          π₂ ∘ k
        ≡⟨ refl ⟩
          g
        ∎
        where
          open ≡-Reasoning
          open _≅_ iso' using (iso₂)
          k : X → Y'
          k x = (f x , (g x , h x))
abstract
  ext : ∀ {i j} → Extensionality i j
  ext h = ext₀ h
        ⊚ ext₀ (λ _ → refl) ⁻¹
  
  ext-id : ∀ {i j}{X : Set i}{Y : Set j}
         → (f : X → Y)
         → ext {f = f} {f} (λ _ → refl) ≡ refl
  ext-id f = left-inverse (ext₀ (λ x → refl))