Martin Escardo, January 2021.
It is possible to work with lists *defined* from the ingredients of
our Spartan MLTT (see the module Fin.lagda). For the moment we are
Athenian in this respect.
\begin{code}
{-# OPTIONS --safe --without-K --no-exact-split #-}
module MLTT.List where
open import MLTT.Spartan
open import MLTT.Bool
open import Naturals.Properties
open import Naturals.Order hiding (minus)
open import Notation.Order
data List {π€} (X : π€ Μ ) : π€ Μ where
[] : List X
_β·_ : X β List X β List X
infixr 3 _β·_
{-# BUILTIN LIST List #-}
length : {X : π€ Μ } β List X β β
length [] = 0
length (x β· xs) = succ (length xs)
course-of-values-induction-on-length
: {X : π€ Μ}
β (P : List X β π₯ Μ )
β ((xs : List X) β ((ys : List X) β length ys < length xs β P ys) β P xs)
β (xs : List X) β P xs
course-of-values-induction-on-length {π€} {π₯} {X} =
course-of-values-induction-on-value-of-function length
Vector' : π€ Μ β β β π€ Μ
Vector' X n = (Ξ£ xs κ List X , length xs οΌ n)
_β·'_ : {X : π€ Μ } {n : β} β X β Vector' X n β Vector' X (succ n)
x β·' (xs , p) = (x β· xs) , ap succ p
equal-heads : {X : π€ Μ } {x y : X} {s t : List X}
β x β· s οΌ y β· t
β x οΌ y
equal-heads refl = refl
equal-tails : {X : π€ Μ } {x y : X} {s t : List X}
β x β· s οΌ y β· t
β s οΌ t
equal-tails refl = refl
equal-head-tail : {X : π€ Μ } {x : X} {s t : List X}
β x β· s οΌ t
β Ξ£ y κ X , Ξ£ t' κ List X , (t οΌ y β· t')
equal-head-tail {π€} {X} {x} {s} {t} refl = x , s , refl
[_] : {X : π€ Μ } β X β List X
[ x ] = x β· []
[]-is-not-cons : {X : π€ Μ } (x : X) (xs : List X)
β [] β x β· xs
[]-is-not-cons x [] ()
[]-is-not-cons x (xβ β· xs) ()
_++_ : {X : π€ Μ } β List X β List X β List X
[] ++ t = t
(x β· s) ++ t = x β· (s ++ t)
infixr 2 _++_
[]-right-neutral : {X : π€ Μ } (s : List X) β s οΌ s ++ []
[]-right-neutral [] = refl
[]-right-neutral (x β· s) = ap (x β·_) ([]-right-neutral s)
++-assoc : {X : π€ Μ } β associative (_++_ {π€} {X})
++-assoc [] t u = refl
++-assoc (x β· s) t u = ap (x β·_) (++-assoc s t u)
foldr : {X : π€ Μ } {Y : π₯ Μ } β (X β Y β Y) β Y β List X β Y
foldr _Β·_ Ξ΅ [] = Ξ΅
foldr _Β·_ Ξ΅ (x β· xs) = x Β· foldr _Β·_ Ξ΅ xs
map : {X : π€ Μ } {Y : π₯ Μ } β (X β Y) β List X β List Y
map f [] = []
map f (x β· xs) = f x β· map f xs
_<$>_ = map
is-non-empty : {X : π€ Μ } β List X β π€ Μ
is-non-empty [] = π
is-non-empty (x β· xs) = π
[]-is-empty : {X : π€ Μ } β Β¬ is-non-empty ([] {π€} {X})
[]-is-empty = π-elim
pattern cons-is-non-empty = β
is-non-empty-++ : {X : π€ Μ } (xs ys : List X)
β is-non-empty xs
β is-non-empty (xs ++ ys)
is-non-empty-++ (x β· xs) ys β = β
empty : {X : π€ Μ } β List X β Bool
empty [] = true
empty (x β· xs) = false
data member {X : π€ Μ } : X β List X β π€ Μ where
in-head : {x : X} {xs : List X} β member x (x β· xs)
in-tail : {x y : X} {xs : List X} β member x xs β member x (y β· xs)
lists-with-members-are-non-empty : {X : π€ Μ }
{y : X}
{xs : List X}
β member y xs
β is-non-empty xs
lists-with-members-are-non-empty in-head = cons-is-non-empty
lists-with-members-are-non-empty (in-tail m) = cons-is-non-empty
member-map : {X : π€ Μ } {Y : π₯ Μ } (f : X β Y) (x : X) (xs : List X)
β member x xs
β member (f x) (map f xs)
member-map f x' (_ β· _) in-head = in-head
member-map f x' (_ β· xs) (in-tail m) = in-tail (member-map f x' xs m)
private
filter-helper : {X : π€ Μ } (p : X β π₯ Μ )
β (x : X)
β p x + Β¬ p x
β List X
β List X
filter-helper p x (inl _) xs = x β· xs
filter-helper p x (inr _) xs = xs
filter : {X : π€ Μ } (p : X β π₯ Μ ) β ((x : X) β p x + Β¬ p x) β List X β List X
filter p Ξ΄ [] = []
filter p Ξ΄ (x β· xs) = filter-helper p x (Ξ΄ x) (filter p Ξ΄ xs)
open import MLTT.Plus-Properties
filter-memberβ : {X : π€ Μ }
(p : X β π₯ Μ )
(Ξ΄ : (x : X) β p x + Β¬ p x)
(y : X)
(xs : List X)
β member y (filter p Ξ΄ xs)
β p y
filter-memberβ {π€} {π₯} {X} p Ξ΄ y (x β· xs) = h x xs (Ξ΄ x)
where
h : (x : X)
(xs : List X)
β (d : p x + Β¬ p x)
β member y (filter-helper p x d (filter p Ξ΄ xs))
β p y
h x xs (inl l) in-head = l
h x xs (inl _) (in-tail m) = filter-memberβ p Ξ΄ y xs m
h x (x' β· xs) (inr _) m = h x' xs (Ξ΄ x') m
filter-memberβ : {X : π€ Μ }
(p : X β π₯ Μ )
(Ξ΄ : (x : X) β p x + Β¬ p x)
(y : X)
(xs : List X)
β p y
β member y xs
β member y (filter p Ξ΄ xs)
filter-memberβ {π€} {π₯} {X} p Ξ΄ y (x β· xs) = h x xs (Ξ΄ x)
where
h : (x : X)
(xs : List X)
β (d : p x + Β¬ p x)
β p y
β member y (x β· xs)
β member y (filter-helper p x d (filter p Ξ΄ xs))
h x xs (inl _) py in-head = in-head
h x (x' β· xs) (inl _) py (in-tail m) = in-tail (h x' xs (Ξ΄ x') py m)
h x xs (inr r) py in-head = π-elim (r py)
h x xs (inr _) py (in-tail m) = filter-memberβ p Ξ΄ y xs py m
member' : {X : π€ Μ } β X β List X β π€ Μ
member' y [] = π
member' y (x β· xs) = (x οΌ y) + member' y xs
member'-map : {X : π€ Μ } {Y : π₯ Μ } (f : X β Y) (x : X) (xs : List X)
β member' x xs
β member' (f x) (map f xs)
member'-map f x' (x β· xs) (inl p) = inl (ap f p)
member'-map f x' (x β· xs) (inr m) = inr (member'-map f x' xs m)
listed : π€ Μ β π€ Μ
listed X = Ξ£ xs κ List X , ((x : X) β member x xs)
listedβΊ : π€ Μ β π€ Μ
listedβΊ X = X Γ listed X
type-from-list : {X : π€ Μ} β List X β π€ Μ
type-from-list {X = X} xs = Ξ£ x κ X , member x xs
type-from-list-is-listed : {X : π€ Μ } (xs : List X)
β listed (type-from-list xs)
type-from-list-is-listed {π€} {X} [] = [] , g
where
g : (Ο : type-from-list []) β member Ο []
g (x , ())
type-from-list-is-listed {π€} {X} (x β· xs) = g
where
h : (x : X) β type-from-list (x β· xs)
h x = x , in-head
t : type-from-list xs β type-from-list (x β· xs)
t (x , m) = x , in-tail m
Ξ± : List (type-from-list xs) β List (type-from-list (x β· xs))
Ξ± Οs = h x β· map t Οs
Ξ² : ((Οs , ΞΌ) : listed (type-from-list xs))
β (Ο : type-from-list (x β· xs)) β member Ο (Ξ± Οs)
Ξ² (Οs , ΞΌ) (y , in-head) = in-head
Ξ² (Οs , ΞΌ) (y , in-tail m) = in-tail (member-map t (y , m) Οs (ΞΌ (y , m)))
f : listed (type-from-list xs) β listed (type-from-list (x β· xs))
f (Οs , ΞΌ) = Ξ± Οs , Ξ² (Οs , ΞΌ)
g : listed (type-from-list (x β· xs))
g = f (type-from-list-is-listed xs)
module _ {X : π€ Μ } where
delete : {n : β}
{y : X}
((xs , _) : Vector' X (succ n))
β member y xs
β Vector' X n
delete {0} _ in-head = [] , refl
delete {0} _ (in-tail _) = [] , refl
delete {succ _} ((_ β· xs) , p) in-head = xs , succ-lc p
delete {succ n} ((x β· xs) , p) (in-tail m) = x β·' delete {n} (xs , succ-lc p) m
module list-util
{π€ : Universe}
{X : π€ Μ }
{{_ : Eq X}}
where
_is-in_ : X β List X β Bool
x is-in [] = false
x is-in (y β· ys) = (x == y) || (x is-in ys)
insert : X β List X β List X
insert x xs = x β· xs
_contained-in_ : List X β List X β Bool
[] contained-in ys = true
(x β· xs) contained-in ys = (x is-in ys) && (xs contained-in ys)
contained-lemmaβ : (x z : X) (xs ys : List X)
β ys contained-in (x β· xs) οΌ true
β ys contained-in (x β· z β· xs) οΌ true
contained-lemmaβ x z xs [] e = e
contained-lemmaβ x z xs (y β· ys) e = Ξ³
where
IH : ys contained-in (x β· xs) οΌ true β ys contained-in (x β· z β· xs) οΌ true
IH = contained-lemmaβ x z xs ys
eβ : (y == x) || (y is-in xs) οΌ true
eβ = prβ (&&-gives-Γ e)
eβ : ys contained-in (x β· xs) οΌ true
eβ = prβ (&&-gives-Γ e)
a : (y == x) || ((y == z) || (y is-in xs)) οΌ true
a = Cases (||-gives-+ eβ)
(Ξ» (e : (y == x) οΌ true) β ||-left-intro ((y == z) || (y is-in xs)) e)
(Ξ» (e : y is-in xs οΌ true) β ||-right-intro {y == x} ((y == z) || (y is-in xs)) (||-right-intro (y is-in xs) e))
b : ys contained-in (x β· z β· xs) οΌ true
b = IH eβ
Ξ³ : ((y == x) || ((y == z) || (y is-in xs))) && (ys contained-in (x β· z β· xs)) οΌ true
Ξ³ = &&-intro a b
contained-lemmaβ : (x : X) (ys : List X)
β ys contained-in (x β· ys) οΌ true
contained-lemmaβ x [] = refl
contained-lemmaβ x (y β· ys) = Ξ³
where
IH : ys contained-in (x β· ys) οΌ true
IH = contained-lemmaβ x ys
a : y == x || (y == y || (y is-in ys)) οΌ true
a = ||-right-intro {y == x} ((y == y) || (y is-in ys)) (||-left-intro (y is-in ys) (==-refl y))
b : ys contained-in (x β· y β· ys) οΌ true
b = contained-lemmaβ x y ys ys IH
Ξ³ : (y == x || (y == y || (y is-in ys))) && (ys contained-in (x β· y β· ys)) οΌ true
Ξ³ = &&-intro a b
some-contained : List (List X) β List X β Bool
some-contained [] ys = false
some-contained (xs β· xss) ys = xs contained-in ys || some-contained xss ys
remove-first : X β List X β List X
remove-first x [] = []
remove-first x (y β· ys) = if x == y then ys else (y β· remove-first x ys)
remove-all : X β List X β List X
remove-all x [] = []
remove-all x (y β· ys) = if x == y then remove-all x ys else (y β· remove-all x ys)
_minus_ : List X β List X β List X
xs minus [] = xs
xs minus (y β· ys) = (remove-all y xs) minus ys
\end{code}
Remove first occurrence:
\begin{code}
remove : X β List X β List X
remove x [] = []
remove x (y β· ys) = if x == y then ys else (y β· remove x ys)
remove-head : (x y : X) (ys : List X)
β (x == y) οΌ true
β remove x (y β· ys) οΌ ys
remove-head x y ys q =
remove x (y β· ys) οΌβ¨ refl β©
(if x == y then ys else (y β· remove x ys)) οΌβ¨ I β©
(if true then ys else (y β· remove x ys)) οΌβ¨ refl β©
ys β
where
I = ap (Ξ» - β if - then ys else (y β· remove x ys)) q
remove-tail : (x y : X) (ys : List X)
β (x == y) οΌ false
β remove x (y β· ys) οΌ y β· remove x ys
remove-tail x y ys q =
remove x (y β· ys) οΌβ¨ refl β©
if x == y then ys else (y β· remove x ys) οΌβ¨ I β©
if false then ys else (y β· remove x ys) οΌβ¨ refl β©
y β· remove x ys β
where
I = ap (Ξ» - β if - then ys else (y β· remove x ys)) q
remove-length : (x : X) (ys : List X)
β member x ys
β (n : β)
β length ys οΌ succ n
β length (remove x ys) οΌ n
remove-length x ys@(z β· zs) m n p = h m n p (x == z) refl
where
h : member x ys
β (n : β)
β length ys οΌ succ n
β (b : Bool) β (x == z) οΌ b β length (remove x ys) οΌ n
h _ n p true q =
length (remove x (z β· zs)) οΌβ¨ ap length (remove-head x z zs q) β©
length zs οΌβ¨ succ-lc p β©
n β
h in-head n p false q =
π-elim (true-is-not-false
(true οΌβ¨ (==-refl x)β»ΒΉ β©
(x == x) οΌβ¨ q β©
false β))
h (in-tail in-head) 0 () false q
h (in-tail (in-tail m)) 0 () false q
h (in-tail m) (succ n) p false q =
length (remove x (z β· zs)) οΌβ¨ I β©
length (z β· remove x zs) οΌβ¨ refl β©
succ (length (remove x zs)) οΌβ¨ II β©
succ n β
where
I = ap length (remove-tail x z zs q)
II = ap succ (remove-length x zs m n (succ-lc p))
delete' : {n : β}
(x : X)
((xs , _) : Vector' X (succ n))
β member x xs
β Vector' X n
delete' {n} x (xs , p) m = remove x xs , remove-length x xs m n p
\end{code}
Added by Ayberk Tosun on 2023-10-16.
\begin{code}
right-concatenation-preserves-membership : {X : π€ Μ } (x : X) (xs ys : List X)
β member x xs β member x (xs ++ ys)
right-concatenation-preserves-membership x xs@(xβ² β· _) ys in-head = in-head
right-concatenation-preserves-membership x xs@(xβ² β· xsβ²) ys (in-tail p) =
in-tail (right-concatenation-preserves-membership x xsβ² ys p)
left-concatenation-preserves-membership : {X : π€ Μ } (x : X) (xs ys : List X)
β member x xs β member x (ys ++ xs)
left-concatenation-preserves-membership x xs [] p = p
left-concatenation-preserves-membership x xs (y β· ys) p = β
where
β : member x (y β· (ys ++ xs))
β = in-tail (left-concatenation-preserves-membership x xs ys p)
++-membershipβ : {X : π€ Μ } (x : X) (xs ys : List X)
β member x (xs ++ ys) β member x xs + member x ys
++-membershipβ x [] zs p = inr p
++-membershipβ x (x β· ys) zs in-head = inl in-head
++-membershipβ x (y β· ys) zs (in-tail p) = cases β β‘ (++-membershipβ x ys zs p)
where
β : member x ys β member x (y β· ys) + member x zs
β p = inl (in-tail p)
β‘ : member x zs β member x (y β· ys) + member x zs
β‘ = inr
\end{code}
Added 2nd April 2024 by Martin Escardo and Paulo Oliva. Ingredients
for the list monad.
\begin{code}
map-++ : {X : π€ Μ } {Y : π₯ Μ }
(f : X β Y)
(xs ys : List X)
β map f (xs ++ ys) οΌ map f xs ++ map f ys
map-++ f [] ys = refl
map-++ f (x β· xs) ys = ap (f x β·_) (map-++ f xs ys)
concat : {X : π€ Μ } β List (List X) β List X
concat [] = []
concat (xs β· xss) = xs ++ concat xss
concat-singletons : {X : π€ Μ }
(xs : List X) β concat (map [_] xs) οΌ xs
concat-singletons [] = refl
concat-singletons (x β· xs) = ap (x β·_) (concat-singletons xs)
concat-++ : {X : π€ Μ }
(xss yss : List (List X))
β concat (xss ++ yss) οΌ concat xss ++ concat yss
concat-++ [] yss = refl
concat-++ (xs β· xss) yss =
concat (xs β· xss ++ yss) οΌβ¨ refl β©
xs ++ concat (xss ++ yss) οΌβ¨ I β©
xs ++ (concat xss ++ concat yss) οΌβ¨ II β©
(xs ++ concat xss) ++ concat yss οΌβ¨ refl β©
concat (xs β· xss) ++ concat yss β
where
I = ap (xs ++_) (concat-++ xss yss)
II = (++-assoc xs (concat xss) (concat yss))β»ΒΉ
\end{code}
The following are the Kleisli extension operations for the list monad
and its associativity law.
\begin{code}
List-ext : {X : π€ Μ } {Y : π₯ Μ }
β (X β List Y) β (List X β List Y)
List-ext f xs = concat (map f xs)
List-ext-unit : {X : π€ Μ } {Y : π₯ Μ }
(f : X β List Y) (x : X)
β f x ++ [] οΌ f x
List-ext-unit f x = ([]-right-neutral (f x))β»ΒΉ
List-ext-assoc
: {X : π€ Μ } {Y : π₯ Μ } {Z : π¦ Μ }
(g : Y β List Z) (f : X β List Y)
(xs : List X)
β List-ext (Ξ» x β List-ext g (f x)) xs οΌ List-ext g (List-ext f xs)
List-ext-assoc g f [] = refl
List-ext-assoc g f (x β· xs) =
List-ext (Ξ» - β List-ext g (f -)) (x β· xs) οΌβ¨ refl β©
List-ext g (f x) ++ List-ext (Ξ» - β List-ext g (f -)) xs οΌβ¨ I β©
List-ext g (f x) ++ List-ext g (List-ext f xs) οΌβ¨ II β©
concat (map g (f x) ++ map g (List-ext f xs)) οΌβ¨ III β©
List-ext g (f x ++ List-ext f xs) οΌβ¨ refl β©
List-ext g (List-ext f (x β· xs)) β
where
I = ap (List-ext g (f x) ++_) (List-ext-assoc g f xs)
II = (concat-++ (map g (f x)) (map g (List-ext f xs)))β»ΒΉ
III = (ap concat (map-++ g (f x) (List-ext f xs)))β»ΒΉ
\end{code}