------------------------------------------------------------------------
-- The double-negation monad
------------------------------------------------------------------------

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

open import Equality

module Double-negation
  {reflexive} (eq :  {a p}  Equality-with-J a p reflexive) where

open import Logical-equivalence using (_⇔_)
open import Prelude

import Accessibility eq as A
open import Bijection eq as B using (_↔_)
open Derived-definitions-and-properties eq
open import Equivalence eq as Eq using (_≃_; Is-equivalence)
open import Equivalence.Path-split eq as PS
  using (Is-∞-extendable-along-[_])
open import Erased.Level-1 eq as E using (Erased)
open import Excluded-middle eq
open import Extensionality eq
open import Function-universe eq hiding (id; _∘_)
open import H-level eq
open import H-level.Closure eq
open import Modality.Basics eq
open import Monad eq

-- The double-negation monad, defined using a wrapper type to make
-- instance resolution easier.

infix 3 ¬¬_

record ¬¬_ {a} (A : Type a) : Type a where
  constructor wrap
  field
    run : ¬ ¬ A

open ¬¬_ public

-- ¬¬ A is a proposition (assuming extensionality).

¬¬-propositional :
   {a} {A : Type a} 
  Extensionality a lzero 
  Is-proposition (¬¬ A)
¬¬-propositional ext _ _ =
  cong wrap $ ¬-propositional ext _ _

-- An extra universe-polymorphic variant of map.

map′ :
   {a b} {@0 A : Type a} {@0 B : Type b} 
  (A  B)  ¬¬ A  ¬¬ B
run (map′ f ¬¬a) = λ ¬b  run ¬¬a  a  ¬b (f a))

-- A variant of bind with extra universe-polymorphism (and some erased
-- arguments).

infixl 5 _>>=′_

_>>=′_ :
   {a b} {@0 A : Type a} {@0 B : Type b} 
  ¬¬ A  (A  ¬¬ B)  ¬¬ B
run (x >>=′ f) = join (map′ (run  f) x)
  where
  join :  {a} {@0 A : Type a}  ¬¬ ¬ A  ¬ A
  join ¬¬¬a = λ a  run ¬¬¬a  ¬a  ¬a a)

-- Instances.

instance

  double-negation-monad :  {}  Raw-monad  (A : Type )  ¬¬ A)
  Raw-monad.return double-negation-monad x .run = _$ x
  Raw-monad._>>=_  double-negation-monad        = _>>=′_

monad :  {} 
        Extensionality  lzero 
        Monad  (A : Type )  ¬¬ A)
Monad.raw-monad      (monad _)         = double-negation-monad
Monad.left-identity  (monad ext) _ _   = ¬¬-propositional ext _ _
Monad.right-identity (monad ext) _     = ¬¬-propositional ext _ _
Monad.associativity  (monad ext) _ _ _ = ¬¬-propositional ext _ _

-- The following variant of excluded middle is provable.

excluded-middle :  {a} {@0 A : Type a}  ¬¬ Dec A
run excluded-middle ¬[a⊎¬a] = ¬[a⊎¬a] (no λ a  ¬[a⊎¬a] (yes a))

-- The following variant of Peirce's law is provable.

call/cc :  {a w} {@0 A : Type a} {Whatever : Type w} 
          ((A  Whatever)  ¬¬ A)  ¬¬ A
run (call/cc hyp) ¬a = run (hyp  a  ⊥-elim (¬a a))) ¬a

-- If one can prove that the empty type is inhabited in the
-- double-negation monad, then the empty type is inhabited.

¬¬¬⊥ :  {}  ¬ (¬¬ ( { = }))
¬¬¬⊥ ¬¬⊥ = run ¬¬⊥ ⊥-elim

-- If the double-negation of a negation can be proved, then the
-- negation itself can be proved.

¬¬¬→¬ :  {a} {A : Type a}  ¬¬ ¬ A  ¬ A
¬¬¬→¬ ¬¬¬a = λ a  ¬¬¬⊥ (¬¬¬a >>= λ ¬a  ⊥-elim (¬a a))

------------------------------------------------------------------------
-- Excluded middle and double-negation elimination

-- Double-negation elimination (roughly as stated in the HoTT book).

Double-negation-elimination : ( : Level)  Type (lsuc )
Double-negation-elimination p =
  {P : Type p}  Is-proposition P  ¬¬ P  P

-- Double-negation elimination is propositional (assuming
-- extensionality).

Double-negation-elimination-propositional :
   {} 
  Extensionality (lsuc )  
  Is-proposition (Double-negation-elimination )
Double-negation-elimination-propositional ext =
  implicit-Π-closure ext 1 λ _ 
  Π-closure (lower-extensionality _ lzero ext) 1 λ P-prop 
  Π-closure (lower-extensionality _ lzero ext) 1 λ _ 
  P-prop

-- In the presence of double-negation elimination ¬¬ A is equivalent
-- to A for propositions A (assuming extensionality).

¬¬≃ :
   {a} {A : Type a} 
  Is-proposition A 
  Double-negation-elimination a 
  (¬¬ A) ↝[ a  lzero ] A
¬¬≃ prop dne =
  generalise-ext?-prop
    (record { to = dne prop; from = return })
    ¬¬-propositional
     _  prop)

-- Excluded middle implies double-negation elimination.

Excluded-middle→Double-negation-elimination :
   {}  Excluded-middle   Double-negation-elimination 
Excluded-middle→Double-negation-elimination em P-prop ¬¬p =
  [ id , ⊥-elim  run ¬¬p ] (em P-prop)

-- Excluded middle is pointwise equivalent to double-negation
-- elimination (assuming extensionality).

Excluded-middle≃Double-negation-elimination :
   {} 
  Extensionality (lsuc ) (lsuc ) 
  Excluded-middle   Double-negation-elimination 
Excluded-middle≃Double-negation-elimination ext =
  _↔_.to (Eq.⇔↔≃
            ext
            (Excluded-middle-propositional
               (lower-extensionality lzero _ ext))
            (Double-negation-elimination-propositional
               (lower-extensionality lzero _ ext)))
    (record
       { to   = Excluded-middle→Double-negation-elimination
       ; from = λ dne P-prop 
                  dne (Dec-closure-propositional
                         (lower-extensionality _ _ ext) P-prop)
                      excluded-middle
       })

------------------------------------------------------------------------
-- The double-negation modality

-- The double-negation monad is a modality (assuming extensionality).
--
-- This fact is taken from "Modalities in Homotopy Type Theory" by
-- Rijke, Shulman and Spitters, but the proof might be different.

¬¬-modality :  {}  Extensionality    Modality 
¬¬-modality {} ext = λ where
    .  ¬¬_

    .η  return

    .Modal  ¬¬-modal

    .Modal-propositional ext 
      Σ-closure 1 (H-level-propositional ext 1) λ prop 
      Π-closure ext 1 λ _ 
      prop

    .Modal-◯  ¬¬-propositional ext₀ , _>>= id

    .Modal-respects-≃ {A} {B} A≃B 
      Σ-map
        (H-level-cong _ 1 A≃B)
        ((¬¬ A  A)  →⟨ (_≃_.to A≃B ∘_)  (_∘ map (_≃_.from A≃B)) ⟩□
         (¬¬ B  B)  )

    .extendable-along-η {A} {P} 
      (∀ x  ¬¬-modal (P x))              →⟨ lemma 
      Is-equivalence (_∘ return)          ↔⟨ inverse $ PS.Is-∞-extendable-along≃Is-equivalence ext ⟩□
      Is-∞-extendable-along-[ return ] P  
  where
  open Modality

  ext₀ = lower-extensionality lzero _ ext

  -- A type A is modal if it is a proposition for which ¬¬ A
  -- implies A.

  ¬¬-modal : Type   Type 
  ¬¬-modal A = Is-proposition A × (¬¬ A  A)

  lemma :
    {A : Type } {P : ¬¬ A  Type } 
    (∀ x  ¬¬-modal (P x)) 
    Is-equivalence  (g :  x  P x)  g  return)
  lemma {A} {P} hyp =
    _≃_.is-equivalence $
    Eq.⇔→≃
      (Π-closure ext 1 λ x 
       hyp x .proj₁)
      (Π-closure ext 1 λ x 
       hyp (return x) .proj₁)
      _
      (((x : A)  P (return x))                  →⟨  f x  map  x  x , f x) x) 
       ((x : ¬¬ A)  ¬¬ ( λ x  P (return x)))  →⟨  f x  hyp x .proj₂ $ map (subst P (¬¬-propositional ext₀ _ _)  proj₂) (f x)) ⟩□
       ((x : ¬¬ A)  P x)                        )

-- The double-negation modality is empty-modal.

¬¬-empty-modal :
   {} (ext : Extensionality  ) 
  Empty-modal (¬¬-modality ext)
¬¬-empty-modal _ =
  ⊥-propositional , ⊥-elim  ¬¬¬⊥

-- The double-negation modality is not left exact (assuming
-- extensionality).

¬¬-not-left-exact :
   {a} 
  Extensionality a a 
  ¬ Left-exact (¬¬_ {a = a})
¬¬-not-left-exact {a} ext =
  Empty-modal→Is-proposition-◯→¬-Left-exact
    (¬¬-empty-modal ext)
    (¬¬-propositional (lower-extensionality lzero _ ext))
  where
  open Modality (¬¬-modality ext)

-- The double-negation modality is not very modal.

¬¬-not-very-modal :
   {} (ext : Extensionality  ) 
  ¬ Very-modal (¬¬-modality ext)
¬¬-not-very-modal {} ext =
  ({A : Type }  ¬¬ (Is-proposition A × (¬¬ A  A)))        →⟨  hyp  hyp) 
  ¬¬ (Is-proposition (  Bool) × (¬¬   Bool    Bool))  →⟨ map′ proj₁ 
  ¬¬ Is-proposition (  Bool)                               →⟨ map′ (H-level-cong _ 1 B.↑↔) 
  ¬¬ Is-proposition Bool                                     →⟨ map′ ¬-Bool-propositional 
  ¬¬                                                        →⟨ ¬¬¬⊥ ⟩□
                                                            

-- If double-negation elimination holds, then the double-negation
-- modality is W-modal.

¬¬-W-modal :
   {} (ext : Extensionality  ) 
  Double-negation-elimination  
  W-modal (¬¬-modality ext)
¬¬-W-modal ext dne {A} {P} (p , _) =
  prop , dne prop
  where
  open Modality (¬¬-modality ext)

  prop : Is-proposition (W A P)
  prop = W-closure ext 0 p

-- The double-negation modality is not accessibility-modal.

¬¬-not-accessibility-modal :
   {} (ext : Extensionality  ) 
  ¬ Modality.Accessibility-modal (¬¬-modality ext)
¬¬-not-accessibility-modal {} ext =
  Is-proposition-◯→¬-Accessibility-modal
    (¬¬-propositional (lower-extensionality lzero _ ext))
  where
  open Modality (¬¬-modality ext)

-- If double-negation elimination holds, then the double-negation
-- modality is accessibility-modal for propositional relations on
-- propositions.

¬¬-accessibility-modal-for-propositions :
   {} {A : Type } {_<_ : A  A  Type }
  (ext : Extensionality  ) 
  Double-negation-elimination  
  Is-proposition A 
  (∀ {x y}  Is-proposition (x < y)) 
  Modality.Accessibility-modal-for (¬¬-modality ext) _<_
¬¬-accessibility-modal-for-propositions {_<_} ext dne prop prop′ =
     acc  Modal→Acc→Acc-[]◯-η (prop , dne prop) (dne prop′) acc)
  , dne (A.Acc-propositional ext)
  where
  open Modality (¬¬-modality ext)

-- The double-negation modality commutes with Σ.

¬¬-commutes-with-Σ :
   {}
  (ext : Extensionality  ) 
  Modality.Commutes-with-Σ (¬¬-modality ext)
¬¬-commutes-with-Σ ext = Modality.commutes-with-Σ (¬¬-modality ext) ext

-- The double-negation modality commutes with Erased.

commutes-with-Erased :
   {} 
  (ext : Extensionality  ) 
  Modality.Commutes-with-Erased (¬¬-modality ext)
commutes-with-Erased {} ext =
  _≃_.is-equivalence $
  Eq.↔→≃
    _
    from
     _  E.[]-cong₁.H-level-Erased
             (E.Extensionality→[]-cong-axiomatisation ext)
             1
             (¬¬-propositional ext₀)
             _ _)
     _  ¬¬-propositional ext₀ _ _)
  where
  open Modality (¬¬-modality ext)

  ext₀ : Extensionality  lzero
  ext₀ = lower-extensionality lzero _ ext

  from : {@0 A : Type }  Erased (¬¬ A)  ¬¬ Erased A
  from {A} =
    Erased (¬¬ A)   →⟨ E.map run 
    Erased (¬ ¬ A)  →⟨ E.Erased-¬↔¬ _ 
    ¬ Erased (¬ A)  →⟨ →-cong-→ (_⇔_.from (E.Erased-¬↔¬ _)) id 
    ¬ ¬ Erased A    →⟨ wrap ⟩□
    ¬¬ Erased A