Martin Escardo, Paulo Oliva, 2024

Non-empty list monad.

\begin{code}

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

open import MLTT.Spartan hiding (J)

module Games.NonEmptyList where

open import Games.Monad
open import UF.Equiv
open import UF.FunExt

data neList (X : Type) : Type where
 [_]  : X → neList X
 _::_ : X → neList X → neList X

infixr 3 _::_
infixr 2 _++_

_++_ : {X : Type} → neList X → neList X → neList X
[ x ] ++ ys     = x :: ys
(x :: xs) ++ ys = x :: (xs ++ ys)

assoc-++ : {X : Type} (xs ys zs : neList X) → (xs ++ ys) ++ zs ＝ xs ++ (ys ++ zs)
assoc-++ [ x ]     ys zs = refl
assoc-++ (x :: xs) ys zs = ap (x ::_) (assoc-++ xs ys zs)

𝕃⁺ : Monad
𝕃⁺ = record {
 functor = neList ;
 η       = [_] ;
 ext     = ext' ;
 ext-η   = ext'-η ;
 unit    = λ f x → refl ;
 assoc   = assoc'
 }
 where
  ext' : {X Y : Type} → (X → neList Y) → neList X → neList Y
  ext' f [ x ]     = f x
  ext' f (x :: xs) = f x ++ ext' f xs

  ext'-++ : {Y Z : Type}
            (g : Y → neList Z)
            (xs ys : neList Y)
          → ext' g xs ++ ext' g ys ＝ ext' g (xs ++ ys)
  ext'-++ g [ x ]     ys = refl
  ext'-++ g (x :: xs) ys =
   ext' g (x :: xs) ++ ext' g ys   ＝⟨ refl ⟩
   (g x ++ ext' g xs) ++ ext' g ys ＝⟨ assoc-++ (g x) (ext' g xs) (ext' g ys) ⟩
   g x ++ (ext' g xs ++ ext' g ys) ＝⟨ ap (g x ++_) (ext'-++ g xs ys) ⟩
   g x ++ ext' g (xs ++ ys)        ＝⟨ refl ⟩
   ext' g (x :: xs ++ ys)          ∎

  ext'-η : {X : Type} → ext' [_] ∼ 𝑖𝑑 (neList X)
  ext'-η [ x ]     = refl
  ext'-η (x :: xs) = ap (x ::_) (ext'-η xs)

  assoc' : {X Y Z : Type}
           (g : Y → neList Z) (f : X → neList Y)
           (xs : neList X)
         → ext' (λ - → ext' g (f -)) xs ＝ ext' g (ext' f xs)
  assoc' g f [ x ]     = refl
  assoc' g f (x :: xs) =
   ext' (λ - → ext' g (f -)) (x :: xs)           ＝⟨ refl ⟩
   ext' g (f x) ++ ext' (λ - → ext' g (f -)) xs  ＝⟨ ap (ext' g (f x) ++_) (assoc' g f xs) ⟩
   ext' g (f x) ++ ext' g (ext' f xs)            ＝⟨ ext'-++ g (f x) (ext' f xs) ⟩
   ext' g (f x ++ ext' f xs)                     ＝⟨ refl ⟩
   ext' g (ext' f (x :: xs))                     ∎

module neList-definitions where

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

 ηᴸ⁺ : {X : Type} → X → neList X
 ηᴸ⁺ = η 𝕃⁺

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

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

\end{code}
