# Lists

```agda
module lists.lists where
```

<details><summary>Imports</summary>

```agda
open import elementary-number-theory.natural-numbers

open import foundation.action-on-higher-identifications-functions
open import foundation.action-on-identifications-functions
open import foundation.cartesian-product-types
open import foundation.contractible-types
open import foundation.coproduct-types
open import foundation.dependent-pair-types
open import foundation.empty-types
open import foundation.equality-dependent-pair-types
open import foundation.equivalences
open import foundation.function-types
open import foundation.functoriality-dependent-pair-types
open import foundation.homotopies
open import foundation.identity-types
open import foundation.maybe
open import foundation.negation
open import foundation.raising-universe-levels
open import foundation.sets
open import foundation.torsorial-type-families
open import foundation.truncated-types
open import foundation.truncation-levels
open import foundation.unit-type
open import foundation.universe-levels
```

</details>

## Idea

The type of lists of elements of a type `A` is defined inductively, with an
empty list and an operation that extends a list with one element from `A`.

## Definition

### The inductive definition of the type of lists

```agda
data list {l : Level} (A : UU l) : UU l where
  nil : list A
  cons : A  list A  list A
{-# BUILTIN LIST list #-}
```

### Predicates on the type of lists

```agda
is-nil-list : {l : Level} {A : UU l}  list A  UU l
is-nil-list l = (l  nil)

is-nonnil-list : {l : Level} {A : UU l}  list A  UU l
is-nonnil-list l = ¬ (is-nil-list l)

is-cons-list : {l : Level} {A : UU l}  list A  UU l
is-cons-list {l1} {A} l = Σ (A × list A)  (a , l')  l  cons a l')
```

## Operations

### Fold

```agda
fold-list :
  {l1 l2 : Level} {A : UU l1} {B : UU l2} (b : B) (μ : A  (B  B)) 
  list A  B
fold-list b μ nil = b
fold-list b μ (cons a l) = μ a (fold-list b μ l)
```

### The dual of `cons`

```agda
snoc : {l : Level} {A : UU l}  list A  A  list A
snoc nil a = cons a nil
snoc (cons b l) a = cons b (snoc l a)
```

### The unit list

```agda
unit-list : {l : Level} {A : UU l}  A  list A
unit-list a = cons a nil
```

### The length of a list

```agda
length-list : {l : Level} {A : UU l}  list A  
length-list = fold-list 0  a  succ-ℕ)
```

### The elementhood predicate on lists

```agda
infix 6 _∈-list_

data _∈-list_ {l : Level} {A : UU l} : A  list A  UU l where
  is-head : (a : A) (l : list A)  a ∈-list (cons a l)
  is-in-tail : (a x : A) (l : list A)  a ∈-list l  a ∈-list (cons x l)
```

## Properties

### A list that uses cons is not nil

```agda
is-nonnil-cons-list :
  {l : Level} {A : UU l} 
  (a : A)  (l : list A)  is-nonnil-list (cons a l)
is-nonnil-cons-list a l ()

is-nonnil-is-cons-list :
  {l : Level} {A : UU l} 
  (l : list A)  is-cons-list l  is-nonnil-list l
is-nonnil-is-cons-list l ((a , l') , refl) q =
  is-nonnil-cons-list a l' q
```

### A list that uses cons is not nil

```agda
is-cons-is-nonnil-list :
  {l : Level} {A : UU l} 
  (l : list A)  is-nonnil-list l  is-cons-list l
is-cons-is-nonnil-list nil p = ex-falso (p refl)
is-cons-is-nonnil-list (cons x l) p = ((x , l) , refl)

head-is-nonnil-list :
  {l : Level} {A : UU l} 
  (l : list A)  is-nonnil-list l  A
head-is-nonnil-list l p =
  pr1 (pr1 (is-cons-is-nonnil-list l p))

tail-is-nonnil-list :
  {l : Level} {A : UU l} 
  (l : list A)  is-nonnil-list l  list A
tail-is-nonnil-list l p =
  pr2 (pr1 (is-cons-is-nonnil-list l p))
```

### Characterizing the identity type of lists

```agda
Eq-list : {l1 : Level} {A : UU l1}  list A  list A  UU l1
Eq-list {l1} nil nil = raise-unit l1
Eq-list {l1} nil (cons x l') = raise-empty l1
Eq-list {l1} (cons x l) nil = raise-empty l1
Eq-list {l1} (cons x l) (cons x' l') = (Id x x') × Eq-list l l'

refl-Eq-list : {l1 : Level} {A : UU l1} (l : list A)  Eq-list l l
refl-Eq-list nil = raise-star
refl-Eq-list (cons x l) = pair refl (refl-Eq-list l)

Eq-eq-list :
  {l1 : Level} {A : UU l1} (l l' : list A)  Id l l'  Eq-list l l'
Eq-eq-list l .l refl = refl-Eq-list l

eq-Eq-list :
  {l1 : Level} {A : UU l1} (l l' : list A)  Eq-list l l'  Id l l'
eq-Eq-list nil nil (map-raise star) = refl
eq-Eq-list nil (cons x l') (map-raise f) = ex-falso f
eq-Eq-list (cons x l) nil (map-raise f) = ex-falso f
eq-Eq-list (cons x l) (cons .x l') (pair refl e) =
  ap (cons x) (eq-Eq-list l l' e)

square-eq-Eq-list :
  {l1 : Level} {A : UU l1} {x : A} {l l' : list A} (p : Id l l') 
  Id
    ( Eq-eq-list (cons x l) (cons x l') (ap (cons x) p))
    ( pair refl (Eq-eq-list l l' p))
square-eq-Eq-list refl = refl

is-section-eq-Eq-list :
  {l1 : Level} {A : UU l1} (l l' : list A) (e : Eq-list l l') 
  Id (Eq-eq-list l l' (eq-Eq-list l l' e)) e
is-section-eq-Eq-list nil nil e = eq-is-contr is-contr-raise-unit
is-section-eq-Eq-list nil (cons x l') e = ex-falso (is-empty-raise-empty e)
is-section-eq-Eq-list (cons x l) nil e = ex-falso (is-empty-raise-empty e)
is-section-eq-Eq-list (cons x l) (cons .x l') (pair refl e) =
  ( square-eq-Eq-list (eq-Eq-list l l' e)) 
  ( eq-pair-eq-fiber (is-section-eq-Eq-list l l' e))

eq-Eq-refl-Eq-list :
  {l1 : Level} {A : UU l1} (l : list A) 
  Id (eq-Eq-list l l (refl-Eq-list l)) refl
eq-Eq-refl-Eq-list nil = refl
eq-Eq-refl-Eq-list (cons x l) = ap² (cons x) (eq-Eq-refl-Eq-list l)

is-retraction-eq-Eq-list :
  {l1 : Level} {A : UU l1} (l l' : list A) (p : Id l l') 
  Id (eq-Eq-list l l' (Eq-eq-list l l' p)) p
is-retraction-eq-Eq-list nil .nil refl = refl
is-retraction-eq-Eq-list (cons x l) .(cons x l) refl =
  eq-Eq-refl-Eq-list (cons x l)

is-equiv-Eq-eq-list :
  {l1 : Level} {A : UU l1} (l l' : list A)  is-equiv (Eq-eq-list l l')
is-equiv-Eq-eq-list l l' =
  is-equiv-is-invertible
    ( eq-Eq-list l l')
    ( is-section-eq-Eq-list l l')
    ( is-retraction-eq-Eq-list l l')

equiv-Eq-list :
  {l1 : Level} {A : UU l1} (l l' : list A)  Id l l'  Eq-list l l'
equiv-Eq-list l l' =
  pair (Eq-eq-list l l') (is-equiv-Eq-eq-list l l')

is-torsorial-Eq-list :
  {l1 : Level} {A : UU l1} (l : list A) 
  is-torsorial (Eq-list l)
is-torsorial-Eq-list {A = A} l =
  is-contr-equiv'
    ( Σ (list A) (Id l))
    ( equiv-tot (equiv-Eq-list l))
    ( is-torsorial-Id l)

is-trunc-Eq-list :
  (k : 𝕋) {l : Level} {A : UU l}  is-trunc (succ-𝕋 (succ-𝕋 k)) A 
  (l l' : list A)  is-trunc (succ-𝕋 k) (Eq-list l l')
is-trunc-Eq-list k H nil nil =
  is-trunc-is-contr (succ-𝕋 k) is-contr-raise-unit
is-trunc-Eq-list k H nil (cons x l') =
  is-trunc-is-empty k is-empty-raise-empty
is-trunc-Eq-list k H (cons x l) nil =
  is-trunc-is-empty k is-empty-raise-empty
is-trunc-Eq-list k H (cons x l) (cons y l') =
  is-trunc-product (succ-𝕋 k) (H x y) (is-trunc-Eq-list k H l l')

is-trunc-list :
  (k : 𝕋) {l : Level} {A : UU l}  is-trunc (succ-𝕋 (succ-𝕋 k)) A 
  is-trunc (succ-𝕋 (succ-𝕋 k)) (list A)
is-trunc-list k H l l' =
  is-trunc-equiv
    ( succ-𝕋 k)
    ( Eq-list l l')
    ( equiv-Eq-list l l')
    ( is-trunc-Eq-list k H l l')

is-set-list :
  {l : Level} {A : UU l}  is-set A  is-set (list A)
is-set-list = is-trunc-list neg-two-𝕋

list-Set : {l : Level}  Set l  Set l
list-Set A = pair (list (type-Set A)) (is-set-list (is-set-type-Set A))
```

### The length operation behaves well with respect to the other list operations

```agda
length-nil :
  {l1 : Level} {A : UU l1} 
  Id (length-list {A = A} nil) zero-ℕ
length-nil = refl

is-nil-is-zero-length-list :
  {l1 : Level} {A : UU l1}
  (l : list A) 
  is-zero-ℕ (length-list l) 
  is-nil-list l
is-nil-is-zero-length-list nil p = refl

is-nonnil-is-nonzero-length-list :
  {l1 : Level} {A : UU l1}
  (l : list A) 
  is-nonzero-ℕ (length-list l) 
  is-nonnil-list l
is-nonnil-is-nonzero-length-list nil p q = p refl
is-nonnil-is-nonzero-length-list (cons x l) p ()

is-nonzero-length-is-nonnil-list :
  {l1 : Level} {A : UU l1}
  (l : list A) 
  is-nonnil-list l 
  is-nonzero-ℕ (length-list l)
is-nonzero-length-is-nonnil-list nil p q = p refl

lenght-tail-is-nonnil-list :
  {l1 : Level} {A : UU l1}
  (l : list A)  (p : is-nonnil-list l) 
  succ-ℕ (length-list (tail-is-nonnil-list l p)) 
    length-list l
lenght-tail-is-nonnil-list nil p = ex-falso (p refl)
lenght-tail-is-nonnil-list (cons x l) p = refl
```

### Head and tail operations

We define the head and tail operations, and we define the operations of picking
and removing the last element from a list.

```agda
head-snoc-list :
  {l : Level} {A : UU l} (l : list A)  A  A
head-snoc-list nil a = a
head-snoc-list (cons h l) a = h

head-list :
  {l1 : Level} {A : UU l1}  list A  list A
head-list nil = nil
head-list (cons a x) = unit-list a

tail-list :
  {l1 : Level} {A : UU l1}  list A  list A
tail-list nil = nil
tail-list (cons a x) = x

last-element-list :
  {l1 : Level} {A : UU l1}  list A  list A
last-element-list nil = nil
last-element-list (cons a nil) = unit-list a
last-element-list (cons a (cons b x)) = last-element-list (cons b x)
```

### Removing the last element of a list

```agda
remove-last-element-list :
  {l1 : Level} {A : UU l1}  list A  list A
remove-last-element-list nil = nil
remove-last-element-list (cons a nil) = nil
remove-last-element-list (cons a (cons b x)) =
  cons a (remove-last-element-list (cons b x))
```

### Properties of heads and tails and their duals

```agda
head-snoc-snoc-list :
  {l1 : Level} {A : UU l1} (x : list A) (a : A) (b : A) 
  head-list (snoc (snoc x a) b)  head-list (snoc x a)
head-snoc-snoc-list nil a b = refl
head-snoc-snoc-list (cons c x) a b = refl

tail-snoc-snoc-list :
  {l1 : Level} {A : UU l1} (x : list A) (a : A) (b : A) 
  tail-list (snoc (snoc x a) b)  snoc (tail-list (snoc x a)) b
tail-snoc-snoc-list nil a b = refl
tail-snoc-snoc-list (cons c x) a b = refl

last-element-snoc :
  {l1 : Level} {A : UU l1} (x : list A) (a : A) 
  Id (last-element-list (snoc x a)) (unit-list a)
last-element-snoc nil a = refl
last-element-snoc (cons b nil) a = refl
last-element-snoc (cons b (cons c x)) a =
  last-element-snoc (cons c x) a
```

### Algebra structure on the type of lists of elements of `A`

```agda
map-algebra-list :
  {l1 : Level} (A : UU l1) 
  Maybe (A × list A)  list A
map-algebra-list A (inl (a , x)) = cons a x
map-algebra-list A (inr star) = nil

map-inv-algebra-list :
  {l1 : Level} (A : UU l1) 
  list A  Maybe (A × list A)
map-inv-algebra-list A nil = inr star
map-inv-algebra-list A (cons a x) = inl (pair a x)

is-section-map-inv-algebra-list :
  {l1 : Level} (A : UU l1) 
  (map-algebra-list A  map-inv-algebra-list A) ~ id
is-section-map-inv-algebra-list A nil = refl
is-section-map-inv-algebra-list A (cons a x) = refl

is-retraction-map-inv-algebra-list :
  {l1 : Level} (A : UU l1) 
  (map-inv-algebra-list A  map-algebra-list A) ~ id
is-retraction-map-inv-algebra-list A (inl (a , x)) = refl
is-retraction-map-inv-algebra-list A (inr star) = refl

is-equiv-map-algebra-list :
  {l1 : Level} (A : UU l1)  is-equiv (map-algebra-list A)
is-equiv-map-algebra-list A =
  is-equiv-is-invertible
    ( map-inv-algebra-list A)
    ( is-section-map-inv-algebra-list A)
    ( is-retraction-map-inv-algebra-list A)
```