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}