Martin Escardo, Paulo Oliva, 2024

Non-empty list monad.

\begin{code}

{-# OPTIONS --safe --without-K #-}

open import MLTT.Spartan hiding (J)

module MonadOnTypes.NonEmptyList where

open import MonadOnTypes.Monad
open import MLTT.List renaming (map to lmap ; map-∘ to lmap-∘)
open import Notation.CanonicalMap
open import UF.Subsingletons

being-non-empty-is-prop : {X : 𝓤 ̇ } (xs : List X)  is-prop (is-non-empty xs)
being-non-empty-is-prop []       = 𝟘-is-prop
being-non-empty-is-prop (x  xs) = 𝟙-is-prop

List⁺ : Type  Type
List⁺ X = Σ xs  List X , is-non-empty xs

module _ {X : Type} where

 [_]⁺ : X  List⁺ X
 [ x ]⁺ = (x  []) , cons-is-non-empty

 head⁺ : List⁺ X  X
 head⁺ ((x  xs) , cons-is-non-empty) = x

 tail⁺ : List⁺ X  List X
 tail⁺ ((x  xs) , cons-is-non-empty) = xs

 cons⁺ : X  List X  List⁺ X
 cons⁺ x xs = (x  xs) , cons-is-non-empty

 underlying-list⁺ : List⁺ X  List X
 underlying-list⁺ = pr₁

 underlying-list⁺-is-non-empty : (xs : List⁺ X)
                                is-non-empty (underlying-list⁺ xs)
 underlying-list⁺-is-non-empty = pr₂

 instance
  canonical-map-List⁺-to-List : Canonical-Map (List⁺ X) (List X)
  ι {{canonical-map-List⁺-to-List}} = underlying-list⁺

 to-List⁺-= : {xs ys : List⁺ X}  ι xs  ι ys  xs  ys
 to-List⁺-= = to-subtype-= being-non-empty-is-prop

head⁺-is-member : {X : Type} (xs : List⁺ X)
                 member (head⁺ xs) (ι xs)
head⁺-is-member ((x  xs) , _) = in-head

List-ext-lemma⁻ : {X Y : Type} (f : X  List⁺ Y) (xs : List X)
                 is-non-empty xs
                 is-non-empty (List-ext (ι  f) xs)
List-ext-lemma⁻ f (x  xs) cons-is-non-empty =
 is-non-empty-++ (ι (f x)) _ (underlying-list⁺-is-non-empty (f x))

𝕃⁺ : Monad
𝕃⁺ = record {
 functor = List⁺ ;
 η       = λ x  (x  []) , cons-is-non-empty ;
 ext     = λ {X} {Y} (f : X  List⁺ Y) (xs : List⁺ X)
             List-ext (ι  f) (ι xs) ,
              List-ext-lemma⁻ f (ι xs) (underlying-list⁺-is-non-empty xs) ;
 ext-η   = λ {X} (xs : List⁺ X)
             to-List⁺-= (concat-singletons (ι xs)) ;
 unit    = λ {X} {Y} (f : X  List⁺ Y) (x : X)
             to-List⁺-= (List-ext-unit (ι  f) x) ;
 assoc   = λ {X} {Y} {Z} (g : Y  List⁺ Z) (f : X  List⁺ Y) (xs : List⁺ X)
             to-List⁺-= (List-ext-assoc (ι  g) (ι  f) (ι xs))
 }

module List⁺-definitions where

 _⊗ᴸ⁺_ : {X : Type} {Y : X  Type}
       List⁺ X
       ((x : X)  List⁺ (Y x))
       List⁺ (Σ x  X , Y x)
 _⊗ᴸ⁺_ = _⊗_ 𝕃⁺

 ηᴸ⁺ : {X : Type}  X  List⁺ X
 ηᴸ⁺ = η 𝕃⁺

 extᴸ⁺ : {X Y : Type}  (X  List⁺ Y)  List⁺ X  List⁺ Y
 extᴸ⁺ = ext 𝕃⁺

 mapᴸ⁺ : {X Y : Type}  (X  Y)  List⁺ X  List⁺ Y
 mapᴸ⁺ = map 𝕃⁺

 lmap⁺ : {X Y : Type} (f : X  Y) (xs : List⁺ X)  List⁺ Y
 lmap⁺ f xs = lmap f (ι xs) ,
              map-is-non-empty f (ι xs) (underlying-list⁺-is-non-empty xs)

 concat⁺-non-empty : {X : Type} (xss : List⁺ (List⁺ X))
                    is-non-empty (concat (lmap ι (ι xss)))
 concat⁺-non-empty (((xs , xs-ne)  xss) , xss-ne) =
  is-non-empty-++ xs (concat (lmap ι xss)) xs-ne

 concat⁺ : {X : Type}  List⁺ (List⁺ X)  List⁺ X
 concat⁺ {X} xss = concat (lmap ι (ι xss)) , concat⁺-non-empty xss

 mapᴸ⁺-lemma : {X Y : Type} (f : X  Y) (xs : List⁺ X)
              mapᴸ⁺ f xs  lmap⁺ f xs
 mapᴸ⁺-lemma f xs = to-List⁺-= (concat-singletons' f (ι xs))

 extᴸ⁺-explicitly : {X Y : Type}
                    (f : X  List⁺ Y)
                    (xs : List⁺ X)
                   extᴸ⁺ f xs  concat⁺ (lmap⁺ f xs)
 extᴸ⁺-explicitly f xs = to-List⁺-= I
  where
   I : concat (lmap (ι  f) (ι xs))  concat (lmap ι (lmap f (ι xs)))
   I = ap concat (lmap-∘ f ι (ι xs))

 open import UF.FunExt

 ⊗ᴸ⁺-explicitly
  : funext₀
   {X : Type} {Y : X  Type}
    (xs : List⁺ X)
    (yf : (x : X)  List⁺ (Y x))
   xs ⊗ᴸ⁺ yf  concat⁺ (lmap⁺  x  lmap⁺  y  x , y) (yf x)) xs)
 ⊗ᴸ⁺-explicitly fe xs yf =
  xs ⊗ᴸ⁺ yf =⟨ refl 
  extᴸ⁺  x  mapᴸ⁺  y  x , y) (yf x)) xs           =⟨ I 
  extᴸ⁺  x  lmap⁺  y  x , y) (yf x)) xs           =⟨ II 
  concat⁺ (lmap⁺  x  lmap⁺  y  x , y) (yf x)) xs) 
   where
    I  = ap  -  extᴸ⁺ - xs)
            (dfunext fe  x  mapᴸ⁺-lemma  y  x , y) (yf x)))
    II = extᴸ⁺-explicitly  x  lmap⁺  y  x , y) (yf x)) xs

 ι-⊗ᴸ⁺-explicitly
  : funext₀
   {X : Type} {Y : X  Type}
    (xs : List⁺ X)
    (ys : (x : X)  List⁺ (Y x))
   ι (xs ⊗ᴸ⁺ ys)  concat (lmap  x  lmap (x ,_) (ι (ys x))) (ι xs))
 ι-⊗ᴸ⁺-explicitly fe xs ys =
   ι (xs ⊗ᴸ⁺ ys)                                             =⟨ I 
   ι (concat⁺ (lmap⁺  x  lmap⁺  y  x , y) (ys x)) xs)) =⟨ refl 
   concat (lmap ι (lmap  x  lmap⁺ (x ,_) (ys x)) (ι xs))) =⟨ II 
   concat (lmap  x  lmap (x ,_) (ι (ys x))) (ι xs))       
    where
     I  = ap ι (⊗ᴸ⁺-explicitly fe xs ys)
     II = ap concat ((lmap-∘  x  lmap⁺ (x ,_) (ys x)) ι (ι xs))⁻¹)

 _+++_ : {X : Type}  List⁺ X  List X  List⁺ X
 (xs , xs-ne) +++ ys = (xs ++ ys) , is-non-empty-++ xs ys xs-ne

 head⁺-of-+++ : {X : Type} (xs : List⁺ X) (ys : List X)
               head⁺ (xs +++ ys)  head⁺ xs
 head⁺-of-+++ ((x  xs) , xs-ne) ys = refl

 head⁺-of-concat⁺ : {X : Type} (xss : List⁺ (List⁺ X))
                   head⁺ (concat⁺ xss)  head⁺ (head⁺ xss)
 head⁺-of-concat⁺ ((xs  xss) , cons-is-non-empty) = head⁺-of-+++ xs (concat (lmap ι xss))

 head⁺-of-lmap⁺ :  {X Y : Type} (f : X  Y) (xs : List⁺ X)
                 head⁺ (lmap⁺ f xs)  f (head⁺ xs)
 head⁺-of-lmap⁺ f ((x  xs) , _) = refl

 split-membership : funext₀
                   {X : Type}
                    {Y : X  Type}
                    (x : X)
                    (y : Y x)
                    (xs : List⁺ X)
                    (yf : (x : X)  List⁺ (Y x))
                   member (x , y) (ι (xs ⊗ᴸ⁺ yf))
                   member x (ι xs) × member y (ι (yf x))
 split-membership fe {X} {Y} x y xs yf m = m₀ , m₁
  where
   f : X  List (Σ x  X , Y x)
   f x = lmap (x ,_) (ι (yf x))

   I : ι (xs ⊗ᴸ⁺ yf)  concat (lmap f (ι xs))
   I = ι-⊗ᴸ⁺-explicitly fe xs yf

   II : member (x , y) (concat (lmap f (ι xs)))
   II = transport (member (x , y)) I m

   III : Σ zs  List (Σ x  X , Y x)
             , member zs (lmap f (ι xs))
             × member (x , y) zs
   III = member-of-concat←
          (x , y)
          (lmap f (ι xs))
          II

   zs : List (Σ x  X , Y x)
   zs = pr₁ III

   III₀ : member zs (lmap f (ι xs))
   III₀ = pr₁ (pr₂ III)

   III₁ : member (x , y) zs
   III₁ = pr₂ (pr₂ III)

   IV : Σ x'  X , member x' (ι xs) × (lmap (x' ,_) (ι (yf x'))  zs)
   IV = member-of-map← f zs (ι xs) III₀

   x' : X
   x' = pr₁ IV

   IV₀ : member x' (ι xs)
   IV₀ = pr₁ (pr₂ IV)

   IV₁ : lmap (x' ,_) (ι (yf x'))  zs
   IV₁ = pr₂ (pr₂ IV)

   V : member (x , y) (lmap (x' ,_) (ι (yf x')))
   V = transport⁻¹ (member (x , y)) IV₁ III₁

   VI : Σ y'  Y x' , member y' (ι (yf x')) × ((x' , y')  (x , y))
   VI = member-of-map← (x' ,_) (x , y) (ι (yf x')) V

   y' : Y x'
   y' = pr₁ VI

   VI₀ : member y' (ι (yf x'))
   VI₀ = pr₁ (pr₂ VI)

   VI₁ : (x' , y')  (x , y)
   VI₁ = pr₂ (pr₂ VI)

   m₀ : member x (ι xs)
   m₀ = transport  -  member - (ι xs)) (ap pr₁ VI₁) IV₀

   VII :  x' y' x y  (x' , y')  (x , y)   member y' (ι (yf x'))  member y (ι (yf x))
   VII x' y' x y refl = id

   m₁ : member y (ι (yf x))
   m₁ = VII x' y' x y VI₁ VI₀

 join-membership : funext₀
                  {X : Type}
                   {Y : X  Type}
                   (x : X)
                   (y : Y x)
                   (xs : List⁺ X)
                   (yf : (x : X)  List⁺ (Y x))
                  member x (ι xs) × member y (ι (yf x))
                  member (x , y) (ι (xs ⊗ᴸ⁺ yf))
 join-membership fe {X} {Y} x y xs yf (m₀ , m₁) = m
  where
   f : X  List (Σ x  X , Y x)
   f x = lmap (x ,_) (ι (yf x))

   I : ι (xs ⊗ᴸ⁺ yf)  concat (lmap f (ι xs))
   I = ι-⊗ᴸ⁺-explicitly fe xs yf

   II : member (x , y) (f x)
   II = member-of-map→ (x ,_) (ι (yf x)) y m₁

   III : member (f x) (lmap f (ι xs))
   III = member-of-map→ f (ι xs) x m₀

   IV : member (x , y) (concat (lmap f (ι xs)))
   IV = member-of-concat→ (x , y) (lmap f (ι xs)) (f x) III II

   m : member (x , y) (ι (xs ⊗ᴸ⁺ yf))
   m = transport (member (x , y)) (I ⁻¹) IV

\end{code}