indexsource

open import 1Lab.Prelude hiding (map)
open import 1Lab.Reflection.Induction

Investigating the fact that Agda’s erasure modality is an open modality. Terminology is borrowed and some proofs are extracted from the paper Modalities in homotopy type theory by Rijke, Shulman and Spitters. The erasure modality was previously investigated in Logical properties of a modality for erasure by Danielsson.

module ErasureOpen where

private variable
   ℓ' : Level
  A B : Type 

Erasure as an open modality

The Erased monadic modality, internalising @0:

record Erased (@0 A : Type ) : Type  where
  constructor [_]
  field
    @0 erased : A

open Erased

η : {@0 A : Type }  A  Erased A
η x = [ x ]

μ : {@0 A : Type }  Erased (Erased A)  Erased A
μ [ [ x ] ] = [ x ]

…is equivalent to the open modality induced by the following subsingleton:

data Compiling : Type where
  @0 compiling : Compiling

Compiling-is-prop : is-prop Compiling
Compiling-is-prop compiling compiling = refl

○_ : Type   Type 
 A = Compiling  A

○'_ :  Type   Type 
○' A = (c : Compiling)  A c

infix 30 ○_ ○'_

○→Erased :  A  Erased A
○→Erased a .erased = a compiling

-- Agda considers clauses that match on erased constructors as erased.
Erased→○ : Erased A   A
Erased→○ a compiling = a .erased

○≃Erased :  A  Erased A
○≃Erased = Iso→Equiv (○→Erased ,
  iso Erased→○  _  refl)  _  funext λ where compiling  refl))

η○ : A   A
η○ a _ = a

Since Agda allows erased matches for the empty type, the empty type is modal; in other words, we are not not Compiling.

¬¬compiling : ¬ ¬ Compiling
¬¬compiling ¬c with ○→Erased ¬c
... | ()

Open and closed modalities

The corresponding closed modality is given by the join with Compiling, which is equivalent to the following higher inductive type.

data ●_ (A : Type ) : Type  where
  -- At runtime, we only have A.
  η● : A   A
  -- At compile time, we also have an erased "cone" that glues all of A together,
  -- so that ● A is contractible.
  @0 tip :  A
  @0 cone : (a : A)  η● a  tip

infix 30 ●_

unquoteDecl ●-elim = make-elim ●-elim (quote ●_)

@0 ●-contr : is-contr ( A)
●-contr {A = A} = contr tip λ a  sym (ps a) where
  ps : (a :  A)  a  tip
  ps = ●-elim cone refl λ a i j  cone a (i  j)

The rest of this file investigates some properties of open and closed modalities that are not specific to the Compiling proposition we use here.

Some common definitions about higher modalities
module Modality
  {○_ :  {}  Type   Type }
  (η○ :  {} {A : Type }  A   A)
  (○-elim :  { ℓ'} {A : Type } {P :  A  Type ℓ'}
           ((a : A)   P (η○ a))  (a :  A)   P a)
  (○-elim-β :  { ℓ'} {A : Type } {P :  A  Type ℓ'} { : (a : A)   P (η○ a)}
             (a : A)  ○-elim {P = P}  (η○ a)   a)
  (○-≡-modal :  {} {A : Type } {x y :  A}  is-equiv (η○ {A = x  y}))
  where

  modal : Type   Type 
  modal A = is-equiv (η○ {A = A})

  modal-map : (A  B)  Type _
  modal-map {B = B} f = (b : B)  modal (fibre f b)

  connected : Type   Type 
  connected A = is-contr ( A)

  connected-map : (A  B)  Type _
  connected-map {B = B} f = (b : B)  connected (fibre f b)

  modal+connected→contr : modal A  connected A  is-contr A
  modal+connected→contr A-mod A-conn = Equiv→is-hlevel 0 (η○ , A-mod) A-conn

  modal+connected→equiv : {f : A  B}  modal-map f  connected-map f  is-equiv f
  modal+connected→equiv f-mod f-conn .is-eqv b = modal+connected→contr (f-mod b) (f-conn b)

  elim-modal
    :  { ℓ'} {A : Type } {P :  A  Type ℓ'}
     (∀ a  modal (P a))
     ((a : A)  P (η○ a))  (a :  A)  P a
  elim-modal P-modal  a = equiv→inverse (P-modal a) (○-elim  a  η○ ( a)) a)

  elim-modal-β
    :  { ℓ'} {A : Type } {P :  A  Type ℓ'} P-modal { : (a : A)  P (η○ a)}
     (a : A)  elim-modal {P = P} P-modal  (η○ a)   a
  elim-modal-β P-modal {} a =
    ap (equiv→inverse (P-modal (η○ a))) (○-elim-β a)
     equiv→unit (P-modal (η○ a)) ( a)

  map : (A  B)   A   B
  map f = ○-elim (η○  f)

  map-≃ : A  B  ( A)  ( B)
  map-≃ e = map (e .fst) , is-iso→is-equiv λ where
    .is-iso.inv  map (Equiv.from e)
    .is-iso.rinv  elim-modal  _  ○-≡-modal) λ b 
      ap (map (e .fst)) (○-elim-β b)  ○-elim-β (Equiv.from e b)  ap η○ (Equiv.ε e b)
    .is-iso.linv  elim-modal  _  ○-≡-modal) λ a 
      ap (map (Equiv.from e)) (○-elim-β a)  ○-elim-β (e .fst a)  ap η○ (Equiv.η e a)

  retract-○→modal : (η⁻¹ :  A  A)  is-left-inverse η⁻¹ η○  modal A
  retract-○→modal η⁻¹ ret = is-iso→is-equiv $
    iso η⁻¹ (elim-modal  _  ○-≡-modal) λ a  ap η○ (ret a)) ret

  retract→modal
    : (f : A  B) (g : B  A)
     is-left-inverse f g  modal A  modal B
  retract→modal {B = B} f g ret A-modal = retract-○→modal η⁻¹ linv where
    η⁻¹ :  B  B
    η⁻¹ = f  elim-modal  _  A-modal) g
    linv : is-left-inverse η⁻¹ η○
    linv b = ap f (elim-modal-β  _  A-modal) b)  ret b

  modal-≃ : B  A  modal A  modal B
  modal-≃ e = retract→modal (Equiv.from e) (Equiv.to e) (Equiv.η e)

  connected-≃ : B  A  connected A  connected B
  connected-≃ e A-conn = Equiv→is-hlevel 0 (map-≃ e) A-conn

  ≡-modal : modal A   {x y : A}  modal (x  y)
  ≡-modal A-modal = modal-≃ (ap-equiv (η○ , A-modal)) ○-≡-modal

  PathP-modal : {A : I  Type }  modal (A i0)   {x y}  modal (PathP A x y)
  PathP-modal {A = A} A-modal {x} {y} = subst modal (sym (PathP≡Path⁻ A x y)) (≡-modal A-modal)

  reflection-modal : modal ( A)
  reflection-modal = is-iso→is-equiv λ where
    .is-iso.inv  ○-elim id
    .is-iso.rinv  elim-modal  _  ○-≡-modal) λ a  ap η○ (○-elim-β a)
    .is-iso.linv  ○-elim-β

  Π-modal : {B : A  Type }  (∀ a  modal (B a))  modal ((a : A)  B a)
  Π-modal B-modal = retract-○→modal
     f a  elim-modal  _  B-modal _) (_$ a) f)
     f  funext λ a  elim-modal-β  _  B-modal _) f)

  Σ-modal : {B : A  Type }  modal A  (∀ a  modal (B a))  modal (Σ A B)
  Σ-modal {B = B} A-modal B-modal = retract-○→modal
    (Equiv.from Σ-Π-distrib
      ( elim-modal  _  A-modal) fst
      , elim-modal  _  B-modal _) λ (a , b) 
          subst B (sym (elim-modal-β  _  A-modal) (a , b))) b))
    λ (a , b) 
         elim-modal-β  _  A-modal) (a , b)
      ,ₚ elim-modal-β  _  B-modal _) (a , b)  to-pathp⁻ refl

  η-connected : connected-map (η○ {A = A})
  η-connected a = contr
    (○-elim {P = fibre η○}  a  η○ (a , refl)) a)
    (elim-modal  _  ○-≡-modal) λ (a' , p) 
      J  a p  ○-elim  x  η○ (x , refl)) a  η○ (a' , p)) (○-elim-β a') p)

  ○Σ○≃○Σ : {B : A  Type }  ( (Σ A λ a   B a))  ( (Σ A B))
  ○Σ○≃○Σ .fst = ○-elim λ (a , b)  map (a ,_) b
  ○Σ○≃○Σ .snd = is-iso→is-equiv λ where
    .is-iso.inv  map (Σ-map₂ η○)
    .is-iso.rinv  elim-modal  _  ○-≡-modal) λ (a , b) 
      ap (○-elim _) (○-elim-β (a , b))  ○-elim-β (a , η○ b)  ○-elim-β b
    .is-iso.linv  elim-modal  _  ○-≡-modal) λ (a , b) 
      ap (map _) (○-elim-β (a , b))  elim-modal
        {P = λ b  ○-elim _ (○-elim _ b)  η○ (a , b)}  _  ○-≡-modal)
         b  ap (○-elim _) (○-elim-β b)  ○-elim-β (a , b)) b

  Σ-connected : {B : A  Type }  connected A  (∀ a  connected (B a))  connected (Σ A B)
  Σ-connected A-conn B-conn = Equiv→is-hlevel 0 (○Σ○≃○Σ e⁻¹)
    (connected-≃ (Σ-contract B-conn) A-conn)

  -- Additional properties of *lex* modalities

  module _ (○-lex :  {} {A : Type } {a b : A}  ( (a  b))  (η○ a  η○ b)) where
    ≡-connected : connected A  {x y : A}  connected (x  y)
    ≡-connected A-conn = Equiv→is-hlevel 0 ○-lex (Path-is-hlevel 0 A-conn)

    PathP-connected : {A : I  Type }  connected (A i0)   {x y}  connected (PathP A x y)
    PathP-connected {A = A} A-conn {x} {y} =
      subst connected (sym (PathP≡Path⁻ A x y)) (≡-connected A-conn)

and are higher modalities, so we can instantiate this module for both of them.

○-elim-○
  :  { ℓ'} {A : Type } {P :  A  Type ℓ'}
   ((a : A)   P (η○ a))  (a :  A)   P a
○-elim-○ {P = P}  a c =
  subst P (funext λ _  ap a (Compiling-is-prop _ _)) ( (a c) c)

○-≡-modal : {x y :  A}  is-equiv (η○ {A = x  y})
○-≡-modal = is-iso→is-equiv λ where
  .is-iso.inv p i compiling  p compiling i compiling
  .is-iso.rinv p i compiling j compiling  p compiling j compiling
  .is-iso.linv p i j compiling  p j compiling

●-elim-●
  :  { ℓ'} {A : Type } {P :  A  Type ℓ'}
   ((a : A)   P (η● a))  (a :  A)   P a
●-elim-●  = ●-elim  tip λ _  is-contr→pathp  _  ●-contr) _ _

●-≡-modal : {x y :  A}  is-equiv (η● {A = x  y})
●-≡-modal = is-iso→is-equiv λ where
  .is-iso.inv  ●-elim id (is-contr→is-prop ●-contr _ _)
    λ p  is-contr→is-set ●-contr _ _ _ _
  .is-iso.rinv  ●-elim  _  refl) (sym (●-contr .paths _))
    λ p  is-set→squarep  _ _  is-contr→is-set ●-contr) _ _ _ _
  .is-iso.linv _  refl

module  = Modality η○ ○-elim-○  _  funext λ _  transport-refl _) ○-≡-modal
module  = Modality η● ●-elim-●  _  refl) ●-≡-modal

Open and closed modalities are lex.

○-lex : {a b : A}   (a  b)  (η○ a  η○ b)
○-lex = funext≃

module ●-ids {A : Type } {a : A} where
  code :  A  Type 
  code = ●-elim  b   (a  b)) (Lift _ )  b  ua (is-contr→≃ ●-contr (hlevel 0)))

  code-refl : code (η● a)
  code-refl = η● refl

  decode :  b  code b  η● a  b
  decode = ●.elim-modal  _  ●.Π-modal λ _  ●-≡-modal)
    λ a  ●.elim-modal  _  ●-≡-modal) (ap η●)

  decode-over :  b (c : code b)  PathP  i  code (decode b c i)) code-refl c
  decode-over = ●.elim-modal  _  ●.Π-modal λ _  ●.PathP-modal ●.reflection-modal)
    λ a  ●.elim-modal  _  ●.PathP-modal ●.reflection-modal)
      λ p i  η● λ j  p (i  j)

  ids : is-based-identity-system (η● a) code code-refl
  ids .to-path {b} = decode b
  ids .to-path-over {b} = decode-over b

●-lex : {a b : A}   (a  b)  (η● a  η● b)
●-lex = based-identity-system-gives-path ●-ids.ids

Some equivalences specific to open and closed modalities:

●-modal A ≃ ○ (is-contr A) ≃ is-contr (○ A) = ○-connected A

@0 ●-modal→contr : ●.modal A  is-contr A
●-modal→contr A-modal = Equiv→is-hlevel 0 (η● , A-modal) ●-contr

contr→●-modal : @0 is-contr A  ●.modal A
contr→●-modal A-contr = ●.retract-○→modal
  (●-elim id (A-contr .centre) λ a  sym (A-contr .paths a))
  λ _  refl

contr→○-connected : @0 is-contr A  ○.connected A
contr→○-connected A-contr = contr (Erased→○ [ A-contr .centre ]) λ a 
  funext λ where compiling  A-contr .paths _

@0 ○-connected→contr : ○.connected A  is-contr A
○-connected→contr A-conn = contr (A-conn .centre compiling) λ a 
  A-conn .paths (η○ a) $ₚ compiling

○-connected→●-modal : ○.connected A  ●.modal A
○-connected→●-modal A-conn = contr→●-modal (○-connected→contr A-conn)

Artin gluing

We prove an Artin gluing theorem: every type A is equivalent to a certain pullback of ○ A and ● A over ● ○ A, which we call Fracture A. Handwaving, this corresponds to decomposing a type into its “compile time” part and its “runtime” part.

○→●○ :  A    A
○→●○ = η●

●→●○ :  A    A
●→●○ = ●.map η○

Fracture : Type   Type 
Fracture A = Σ ( A ×  A) λ (o , c)  ○→●○ o  ●→●○ c

module _ {A : Type } where
  fracture : A  Fracture A
  fracture a = (η○ a , η● a) , refl

The idea is to prove that the fibres of the fracture map are both -modal and -connected, and hence contractible.

For the modal part, we observe that an element of the fibre of fracture at a triple (o : ○ A, c : ● A, p) can be rearranged into an element of the fibre of η○ at o (which is -connected, hence -modal) together with a dependent path whose type is -modal by standard results about higher modalities.

  fracture-modal : ●.modal-map fracture
  fracture-modal ((o , c) , p) = ●.modal-≃ e $
    ●.Σ-modal (○-connected→●-modal (○.η-connected _)) λ _ 
      ●.PathP-modal $ ●.Σ-modal ●.reflection-modal λ _  ●-≡-modal
    where
      e : fibre fracture ((o , c) , p)
         Σ (fibre η○ o) λ (a , q) 
          PathP  i  Σ ( A) λ c  ○→●○ (q i)  ●→●○ c) (η● a , refl) (c , p)
      e = Σ-ap-snd  _  ap-equiv (Σ-assoc e⁻¹) ∙e Iso→Equiv Σ-pathp-iso e⁻¹) ∙e Σ-assoc

Almost symmetrically, for the connected part, we rearrange the fibre into an element of the fibre of η● at c (which is -connected) together with a dependent path in the fibres of ○→●○. Since the latter is defined as η● its fibres are -connected as well, hence the path type is -connected because is lex.

  fracture-connected : ●.connected-map fracture
  fracture-connected ((o , c) , p) = ●.connected-≃ e $
    ●.Σ-connected (●.η-connected _) λ _ 
      ●.PathP-connected ●-lex (●.η-connected _)
    where
      e : fibre fracture ((o , c) , p)
         Σ (fibre η● c) λ (a , q) 
          PathP  i  Σ ( A) λ o  ○→●○ o  ●→●○ (q i)) (η○ a , refl) (o , p)
      e = Σ-ap-snd  _  ap-equiv (Σ-ap-fst ×-swap ∙e Σ-assoc e⁻¹) ∙e Iso→Equiv Σ-pathp-iso e⁻¹) ∙e Σ-assoc

  fracture-is-equiv : is-equiv fracture
  fracture-is-equiv = ●.modal+connected→equiv fracture-modal fracture-connected

  Artin-gluing : A  Fracture A
  Artin-gluing = fracture , fracture-is-equiv