{- Voevodsky's proof that univalence implies funext -}

{-# OPTIONS --safe #-}

module Cubical.Experiments.FunExtFromUA where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Univalence

variable
  ℓ' : Level
_∼_ : {X : Type } {A : X  Type ℓ'}  (f g : (x : X)  A x)  Type (ℓ-max  ℓ')
f  g =  x  f x  g x

funext :   ℓ'  Type (ℓ-suc(ℓ-max  ℓ'))
funext  ℓ' = {X : Type } {Y : Type ℓ'} {f g : X  Y}  f  g  f  g


pre-comp-is-equiv : (X Y : Type ) (f : X  Y) (Z : Type )
                   isEquiv f
                   isEquiv  (g : Y  Z)  g  f)
pre-comp-is-equiv {} X Y f Z e = elimEquivFun P r (f , e)
 where
  P : (X : Type )  (X  Y)  Type 
  P X f = isEquiv  (g : Y  Z)  g  f)
  r : P Y  x  x)
  r = idIsEquiv (Y  Z)

leftCancellable : {X : Type } {Y : Type ℓ'}  (X  Y)  Type (ℓ-max  ℓ')
leftCancellable f =  {x x'}  f x  f x'  x  x'

equivLC : {X : Type } {Y : Type ℓ'} (f : X  Y)  isEquiv f  leftCancellable f
equivLC f e {x} {x'} p i = hcomp  j  \ {(i = i0)  retEq (f , e) x j ;
                                           (i = i1)  retEq (f , e) x' j})
                                 (invEq (f , e) (p i))

univalence-gives-funext : funext ℓ' 
univalence-gives-funext {ℓ'} {} {X} {Y} {f₀} {f₁} = γ
 where
  Δ = Σ[ y₀  Y ] Σ[ y₁  Y ] y₀  y₁

  δ : Y  Δ
  δ y = (y , y , refl)

  π₀ π₁ : Δ  Y
  π₀ (y₀ , y₁ , p) = y₀
  π₁ (y₀ , y₁ , p) = y₁

  δ-is-equiv : isEquiv δ
  δ-is-equiv = isoToIsEquiv (iso δ π₀ ε η)
   where
    η : (y : Y)  π₀ (δ y)  y
    η y = refl
    ε : (d : Δ)  δ (π₀ d)  d
    ε (y₀ , y₁ , p) i = y₀ , p i , λ j  p (i  j)

  φ : (Δ  Y)  (Y  Y)
  φ π = π  δ

  e : isEquiv φ
  e = pre-comp-is-equiv Y Δ δ Y δ-is-equiv

  p : φ π₀  φ π₁
  p = refl

  q : π₀  π₁
  q = equivLC φ e p

  g : (h : f₀  f₁) (π : Δ  Y) (x : X)  Y
  g = λ h π x  π (f₀ x , f₁ x , h x)

  γ : f₀  f₁  f₀  f₁
  γ h = cong (g h) q

  γ' : f₀  f₁  f₀  f₁
  γ' h = f₀                              ≡⟨ refl 
          x  f₀ x)                    ≡⟨ refl 
          x  π₀ (f₀ x , f₁ x , h x))  ≡⟨ cong (g h) q 
          x  π₁ (f₀ x , f₁ x , h x))  ≡⟨ refl 
          x  f₁ x)                    ≡⟨ refl 
         f₁                              

{- Experiment testing univalence via funext -}

private

  data  : Type₀ where
   zero : 
   succ :   

  f g :   

  f n = n

  g zero = zero
  g (succ n) = succ (g n)

  h : (n : )  f n  g n
  h zero = refl
  h (succ n) = cong succ (h n)

  p : f  g
  p = univalence-gives-funext h

  five : 
  five = succ (succ (succ (succ (succ zero))))

  a : Σ   n  f n  five)
  a = five , refl

  b : Σ   n  g n  five)
  b = subst  -  Σ   n  - n  five)) p a

  c : fst b  five
  c = refl

{- It works, fast. -}