{-# OPTIONS --without-K --rewriting #-}
open import lib.Basics
open import lib.types.Sigma
open import lib.types.Bool
open import lib.types.Int
module lib.types.List where
infixr 60 _::_
data List {i} (A : Type i) : Type i where
nil : List A
_::_ : A → List A → List A
module _ {i} {A : Type i} where
infixr 80 _++_
_++_ : List A → List A → List A
nil ++ l = l
(x :: l₁) ++ l₂ = x :: (l₁ ++ l₂)
snoc : List A → A → List A
snoc l a = l ++ (a :: nil)
++-unit-r : ∀ l → l ++ nil == l
++-unit-r nil = idp
++-unit-r (a :: l) = ap (a ::_) $ ++-unit-r l
++-assoc : ∀ l₁ l₂ l₃ → (l₁ ++ l₂) ++ l₃ == l₁ ++ (l₂ ++ l₃)
++-assoc nil l₂ l₃ = idp
++-assoc (x :: l₁) l₂ l₃ = ap (x ::_) (++-assoc l₁ l₂ l₃)
module _ {j} (P : A → Type j) where
data Any : List A → Type (lmax i j) where
here : ∀ {a} {l} → P a → Any (a :: l)
there : ∀ {a} {l} → Any l → Any (a :: l)
data All : List A → Type (lmax i j) where
nil : All nil
_::_ : ∀ {a} {l} → P a → All l → All (a :: l)
Any-dec : (∀ a → Dec (P a)) → (∀ l → Dec (Any l))
Any-dec _ nil = inr λ{()}
Any-dec dec (a :: l) with dec a
... | inl p = inl $ here p
... | inr ¬p with Any-dec dec l
... | inl ∃p = inl $ there ∃p
... | inr ¬∃p = inr λ{(here p) → ¬p p; (there ∃p) → ¬∃p ∃p}
Any-++-l : ∀ l₁ l₂ → Any l₁ → Any (l₁ ++ l₂)
Any-++-l _ _ (here p) = here p
Any-++-l _ _ (there ∃p) = there (Any-++-l _ _ ∃p)
Any-++-r : ∀ l₁ l₂ → Any l₂ → Any (l₁ ++ l₂)
Any-++-r nil _ ∃p = ∃p
Any-++-r (a :: l) _ ∃p = there (Any-++-r l _ ∃p)
Any-++ : ∀ l₁ l₂ → Any (l₁ ++ l₂) → Any l₁ ⊔ Any l₂
Any-++ nil l₂ ∃p = inr ∃p
Any-++ (a :: l₁) l₂ (here p) = inl (here p)
Any-++ (a :: l₁) l₂ (there ∃p) with Any-++ l₁ l₂ ∃p
... | inl ∃p₁ = inl (there ∃p₁)
... | inr ∃p₂ = inr ∃p₂
infix 80 _∈_
_∈_ : A → List A → Type i
a ∈ l = Any (_== a) l
∈-dec : has-dec-eq A → ∀ a l → Dec (a ∈ l)
∈-dec dec a l = Any-dec (_== a) (λ a' → dec a' a) l
∈-++-l : ∀ a l₁ l₂ → a ∈ l₁ → a ∈ (l₁ ++ l₂)
∈-++-l a = Any-++-l (_== a)
∈-++-r : ∀ a l₁ l₂ → a ∈ l₂ → a ∈ (l₁ ++ l₂)
∈-++-r a = Any-++-r (_== a)
∈-++ : ∀ a l₁ l₂ → a ∈ (l₁ ++ l₂) → (a ∈ l₁) ⊔ (a ∈ l₂)
∈-++ a = Any-++ (_== a)
module _ {j} {B : Type j} (f : A → B → B) where
foldr : B → List A → B
foldr b nil = b
foldr b (a :: l) = f a (foldr b l)
foldr-++ : ∀ b l₁ l₂
→ foldr b (l₁ ++ l₂) == foldr (foldr b l₂) l₁
foldr-++ b nil l₂ = idp
foldr-++ b (a :: l₁) l₂ = ap (f a) (foldr-++ b l₁ l₂)
module _ (f : A → A → A) where
foldr' : A → List A → A
foldr' d nil = d
foldr' _ (a :: nil) = a
foldr' d (a :: l@(_ :: _)) = f a (foldr' d l)
foldr'=foldr : ∀ d → (∀ a → f a d == a)
→ (l : List A)
→ foldr' d l == foldr f d l
foldr'=foldr d is-unit-r nil = idp
foldr'=foldr d is-unit-r (a :: nil) = ! (is-unit-r a)
foldr'=foldr d is-unit-r (a :: l@(_ :: _)) =
ap (f a) (foldr'=foldr d is-unit-r l)
length : List A → ℕ
length = foldr (λ _ n → S n) 0
filter : ∀ {j k} {Keep : A → Type j} {Drop : A → Type k}
→ ((a : A) → Keep a ⊔ Drop a) → List A → List A
filter p nil = nil
filter p (a :: l) with p a
... | inl _ = a :: filter p l
... | inr _ = filter p l
reverse : List A → List A
reverse nil = nil
reverse (x :: l) = snoc (reverse l) x
reverse-snoc : ∀ a l → reverse (snoc l a) == a :: reverse l
reverse-snoc a nil = idp
reverse-snoc a (b :: l) = ap (λ l → snoc l b) (reverse-snoc a l)
reverse-reverse : ∀ l → reverse (reverse l) == l
reverse-reverse nil = idp
reverse-reverse (a :: l) = reverse-snoc a (reverse l) ∙ ap (a ::_) (reverse-reverse l)
List= : ∀ (l₁ l₂ : List A) → Type i
List= nil nil = Lift ⊤
List= nil (y :: l₂) = Lift ⊥
List= (x :: l₁) nil = Lift ⊥
List= (x :: l₁) (y :: l₂) = (x == y) × (l₁ == l₂)
List=-in : ∀ {l₁ l₂ : List A} → l₁ == l₂ → List= l₁ l₂
List=-in {l₁ = nil} idp = lift unit
List=-in {l₁ = x :: l} idp = idp , idp
List=-out : ∀ {l₁ l₂ : List A} → List= l₁ l₂ → l₁ == l₂
List=-out {l₁ = nil} {l₂ = nil} _ = idp
List=-out {l₁ = nil} {l₂ = y :: l₂} (lift ())
List=-out {l₁ = x :: l₁} {l₂ = nil} (lift ())
List=-out {l₁ = x :: l₁} {l₂ = y :: l₂} (x=y , l₁=l₂) = ap2 _::_ x=y l₁=l₂
module _ {i j} {A : Type i} {B : Type j} (f : A → B) where
map : List A → List B
map nil = nil
map (a :: l) = f a :: map l
map-++ : ∀ l₁ l₂ → map (l₁ ++ l₂) == map l₁ ++ map l₂
map-++ nil l₂ = idp
map-++ (x :: l₁) l₂ = ap (f x ::_) (map-++ l₁ l₂)
reverse-map : ∀ l → reverse (map l) == map (reverse l)
reverse-map nil = idp
reverse-map (x :: l) =
snoc (reverse (map l)) (f x)
=⟨ ap (λ l' → snoc l' (f x)) (reverse-map l) ⟩
snoc (map (reverse l)) (f x)
=⟨ idp ⟩
map (reverse l) ++ map (x :: nil)
=⟨ ! (map-++ (reverse l) (x :: nil)) ⟩
map (reverse l ++ (x :: nil))
=⟨ idp ⟩
map (reverse (x :: l)) =∎
module _ {i} {A : Type i} where
concat : List (List A) → List A
concat l = foldr _++_ nil l