module Data.Maybe.Properties where

Properties of Maybe🔗

Path space🔗

We can use these lemmas to characterise the path space of Maybe A in terms of the path space of A. This involves a standard encode-decode argument: for a more in-depth explanation, see Data.List.

module MaybePath {} {A : Type } where
  Code : Maybe A  Maybe A  Type _
  Code (just x) (just y) = x  y
  Code (just x) nothing  = Lift _ 
  Code nothing (just y)  = Lift _ 
  Code nothing nothing   = Lift _ 
The rest of this argument is standard, so we omit it.
  refl-code :  x  Code x x
  refl-code (just x) = refl
  refl-code nothing = lift tt

  decode :  x y  Code x y  x  y
  decode (just x) (just y) p = ap just p
  decode nothing nothing _ = refl

  encode :  x y  x  y  Code x y
  encode (just x) (just y) p = just-inj p
  encode (just x) nothing p = absurd (just≠nothing p)
  encode nothing (just x) p = absurd (nothing≠just p)
  encode nothing nothing p = lift tt

  encode-refl :  {x}  encode x x refl  refl-code x
  encode-refl {x = just x} = refl
  encode-refl {x = nothing} = refl

  decode-refl :  {x}  decode x x (refl-code x)  refl
  decode-refl {x = just x} = refl
  decode-refl {x = nothing} = refl

  decode-encode :  {x y}  (p : x  y)  decode x y (encode x y p)  p
  decode-encode {x = x} =
    J  y' p  decode x y' (encode x y' p)  p)
      (ap (decode x x) encode-refl  decode-refl)

  encode-decode :  {x y}  (p : Code x y)  encode x y (decode x y p)  p
  encode-decode {just x} {just y} p = refl
  encode-decode {nothing} {nothing} p = refl

  Path≃Code :  x y  (x  y)  Code x y
  Path≃Code x y =
    Iso→Equiv (encode x y , iso (decode x y) encode-decode decode-encode)

  Code-is-hlevel
    : {x y : Maybe A} (n : Nat)
     is-hlevel A (2 + n)
     is-hlevel (Code x y) (1 + n)
  Code-is-hlevel {x = just x} {y = just y} n ahl = ahl x y
  Code-is-hlevel {x = just x} {y = nothing} n ahl = hlevel (1 + n)
  Code-is-hlevel {x = nothing} {y = just x} n ahl = hlevel (1 + n)
  Code-is-hlevel {x = nothing} {y = nothing} n ahl = hlevel (1 + n)

Now that we’ve characterised the path space, we can determine the h-level of Maybe.

Maybe-is-hlevel
  : (n : Nat)
   is-hlevel A (2 + n)
   is-hlevel (Maybe A) (2 + n)
Maybe-is-hlevel n ahl x y =
  Equiv→is-hlevel (1 + n) (MaybePath.Path≃Code x y) (MaybePath.Code-is-hlevel n ahl)

We also note that just is an embedding; this follows immediately from the characterisation of the path space.

just-cancellable :  {x y : A}  (just x  just y)  (x  y)
just-cancellable {x = x} {y = y} = MaybePath.Path≃Code (just x) (just y)

just-is-embedding : is-embedding (just {A = A})
just-is-embedding = cancellable→embedding just-cancellable

This lets us show that Maybe reflects h-levels.

Maybe-reflect-hlevel
  : (n : Nat)
   is-hlevel (Maybe A) (2 + n)
   is-hlevel A (2 + n)
Maybe-reflect-hlevel n mhl =
  embedding→is-hlevel {f = just} (1 + n) just-is-embedding mhl

Discreteness🔗

If Maybe A is discrete, then A must also be discrete. This follows from the fact that just is injective.

Maybe-reflect-discrete
  : Discrete (Maybe A)
   Discrete A
Maybe-reflect-discrete eq? = Discrete-inj just just-inj eq?

Misc. properties🔗

If A is empty, then a Maybe A must be nothing.

refute-just : ¬ A  (x : Maybe A)  x  nothing
refute-just ¬a (just a) = absurd (¬a a)
refute-just ¬a nothing = refl

As a corollary, if A is empty, then Maybe A is contractible.

empty→maybe-is-contr : ¬ A  is-contr (Maybe A)
empty→maybe-is-contr ¬a .centre = nothing
empty→maybe-is-contr ¬a .paths x = sym $ refute-just ¬a x

Next, note that map is functorial.

map-id :  {} {A : Type } (x : Maybe A)  map id x  x
map-id (just x) = refl
map-id nothing = refl

map-∘
  :  { ℓ' ℓ''} {A : Type } {B : Type ℓ'} {C : Type ℓ''} {f : B  C} {g : A  B}
   (x : Maybe A)
   map (f  g) x  map f (map g x)
map-∘ (just x) = refl
map-∘ nothing = refl

Furthermore, <|> is left and right unital, associative, and is preserved by map.

<|>-idl :  {A : Type }  (x : Maybe A)  (nothing <|> x)  x
<|>-idl x = refl

<|>-idr :  {A : Type }  (x : Maybe A)  (x <|> nothing)  x
<|>-idr (just x) = refl
<|>-idr nothing = refl

<|>-assoc
  :  {A : Type }
   (x y z : Maybe A)
   (x <|> (y <|> z))  ((x <|> y) <|> z)
<|>-assoc (just x) y z = refl
<|>-assoc nothing y z = refl

map-<|>
  :  {A : Type } {B : Type ℓ'} {f : A  B}
   (x y : Maybe A)
   map f (x <|> y)  (map f x <|> map f y)
map-<|> (just x) y = refl
map-<|> nothing y = refl

Injectivity🔗

We can prove that the Maybe type constructor, considered as a function from a universe to itself, is injective.

Maybe-injective : Maybe A  Maybe B  A  B
Maybe-injective e = Iso→Equiv (a→b , iso b→a (lemma e) il) where
  a→b = maybe-injective e
  b→a = maybe-injective (Equiv.inverse e)

  module _ (e : Maybe A  Maybe B) where abstract
    private
      module e = Equiv e
      module e⁻¹ = Equiv e.inverse

    lemma : is-right-inverse (maybe-injective (Equiv.inverse e)) (maybe-injective e)
    lemma x with inspect (e.from (just x))
    lemma x | just y , p with inspect (e.to (just y))
    lemma x | just y , p | just z  , q = just-inj (sym q  ap e.to (sym p)  e.ε _)
    lemma x | just y , p | nothing , q with inspect (e.to nothing)
    lemma x | just y , p | nothing , q | nothing , r = absurd (just≠nothing (e.injective₂ q r))
    lemma x | just y , p | nothing , q | just z  , r = absurd (nothing≠just (sym q  ap e.to (sym p)  e.ε _))
    lemma x | nothing , p with inspect (e.from nothing)
    lemma x | nothing , p | nothing , q = absurd (just≠nothing (e⁻¹.injective₂ p q))
    lemma x | nothing , p | just y , q with inspect (e.to (just y))
    lemma x | nothing , p | just y , q | just z  , r = absurd (just≠nothing (sym r  ap e.to (sym q)  e.ε _))
    lemma x | nothing , p | just y , q | nothing , r with inspect (e.to nothing)
    lemma x | nothing , p | just y , q | nothing , r | nothing , s = absurd (just≠nothing (e.injective₂ r s))
    lemma x | nothing , p | just y , q | nothing , r | just z , s = just-inj (sym s  ap e.to (sym p)  e.ε _)

  abstract
    il : is-left-inverse b→a a→b
    il = p' where
      p : is-right-inverse (maybe-injective (Equiv.inverse (Equiv.inverse e))) (maybe-injective (Equiv.inverse e))
      p = lemma (Equiv.inverse e)

      p' : is-right-inverse (maybe-injective e) (maybe-injective (Equiv.inverse e))
      p' = subst
         e'  is-right-inverse (maybe-injective e') (maybe-injective (Equiv.inverse e)))
        {Equiv.inverse (Equiv.inverse e)} {e}
        trivial! p