{-# OPTIONS --type-in-type
#-}
open import NeilPrelude
open import Recursion
open import List
open import Nat
module ListProps where
module ListPropsAux {A : Set} where
∷-inj : Injective2 {A} _∷_
∷-inj refl = refl , refl
∷-cong : Congruent2 {A} _∷_
∷-cong = cong2 _∷_
∷-congL : Congruent2L {A} _∷_
∷-congL = cong2L _∷_
∷-congR : Congruent2R {A} _∷_
∷-congR = cong2R _∷_
++assoc : {bs cs : List A} → (as : List A) → (as ++ bs) ++ cs ≡ as ++ bs ++ cs
++assoc = listrec refl ∷-congL
++[]' : (as : List A) → as ++ [] ≡ as
++[]' = listrec refl ∷-congL
++[] : {as : List A} → as ++ [] ≡ as
++[] {as} = ++[]' as
import Monoid
open Monoid _++_ (λ {as} → ++assoc as) [] refl ++[] public
import SemiGroup
open SemiGroup _++_ (λ {as} → ++assoc as) public
listIdem : {f : A → A} → ({a : A} → f (f a) ≡ f a) → (as : List A) → map f (map f as) ≡ map f as
listIdem eIdem = listrec refl (∷-cong eIdem)
++length : {bs : List A} → (as : List A) → length (as ++ bs) ≡ length as + length bs
++length = listrec refl (cong S)
++lengthC : {bs : List A} → (as : List A) → length as + length bs ≡ length (as ++ bs)
++lengthC = sym ∘' ++length
+++length : {cs : List A} → (as bs : List A) → length (as ++ bs ++ cs) ≡ length as + length bs + length cs
+++length as bs = trans2 (cong length (assocR {as})) (++length (as ++ bs)) (cong2 _+_ (++length as) refl)
+++lengthC : {cs : List A} → (as bs : List A) → length as + length bs + length cs ≡ length (as ++ bs ++ cs)
+++lengthC as bs = sym (+++length as bs)
lengthZero : {as : List A} → length as ≡ O → as ≡ []
lengthZero {[]} _ = refl
lengthZero {_ ∷ _} ()
mapId' : (as : List A) → map id as ≡ as
mapId' = listrec refl ∷-congL
mapId : {as : List A} → map id as ≡ as
mapId {as} = mapId' as
++rev : {as : List A} → (bs : List A) → rev as bs ≡ reverse bs ++ as
++rev [] = refl
++rev (b ∷ bs) = trans2 (++rev bs) (assocR {reverse bs}) (cong2R _++_ (sym (++rev bs)))
slowReverse : List A → List A
slowReverse [] = []
slowReverse (a ∷ as) = slowReverse as ++ [ a ]
reversesEq : (as : List A) → reverse as ≡ slowReverse as
reversesEq = listrec' refl (λ _ as hyp → trans (++rev as) (cong2R _++_ hyp))
++reverseAux : {a : A} → {bs : List A} → (as : List A) → reverse (a ∷ as ++ bs) ≡ (reverse (as ++ bs)) ++ [ a ]
++reverseAux {a} {bs} as = trans (reversesEq (a ∷ as ++ bs)) (cong2R _++_ (sym (reversesEq (as ++ bs))))
++reverse : {bs : List A} → (as : List A) → reverse (as ++ bs) ≡ reverse bs ++ reverse as
++reverse {bs} = listrec' (sym ++[]) (λ _ as hyp → trans3 (++reverseAux as) (cong2R _++_ hyp) (++assoc (reverse bs)) (cong (_++_ (reverse bs)) (sym (++rev as))))
revrev' : (as : List A) → reverse (reverse as) ≡ as
revrev' = listrec' refl (λ a as hyp → trans2 (cong reverse (reversesEq (a ∷ as))) (++reverse (slowReverse as)) (cong (_∷_ a) (trans (cong reverse (sym (reversesEq as))) hyp)))
revrev : {as : List A} → reverse (reverse as) ≡ as
revrev {as} = revrev' as
reverseEq : {as bs : List A} → reverse as ≡ reverse bs → as ≡ bs
reverseEq eq = trans2 (sym revrev) (cong reverse eq) revrev
++reverseAuxR : {as bs : List A} → {b : A} → reverse as ++ b ∷ bs ≡ rev [ b ] as ++ bs
++reverseAuxR {as} {bs} = trans (assocR {rev [] as}) (cong (flip _++_ bs) (sym (++rev as)))
++cancL : {bs cs : List A} → (as : List A) → as ++ bs ≡ as ++ cs → bs ≡ cs
++cancL = listrec id (_⋙_ (snd ∘ ∷-inj))
++cancR : {bs cs : List A} → (as : List A) → as ++ cs ≡ bs ++ cs → as ≡ bs
++cancR {bs} {cs} as eq = reverseEq (++cancL (reverse cs) (trans2 (sym (++reverse as)) (cong reverse eq) (++reverse bs)))
import Cancellative
open Cancellative _++_ (λ {as} → ++cancL as) (λ {as} → ++cancR as) public
++eq[] : {as bs : List A} → as ++ bs ≡ [] → as ≡ [] × bs ≡ []
++eq[] {[]} eq = refl , eq
++eq[] {_ ∷ _} ()
concatMapWrap' : (as : List A) → concat (map wrap as) ≡ as
concatMapWrap' = listrec refl ∷-congL
concatMapWrap : {as : List A} → concat (map wrap as) ≡ as
concatMapWrap {as} = concatMapWrap' as
concat++ : {bs : List (List A)} → (as : List (List A)) → concat (as ++ bs) ≡ concat as ++ concat bs
concat++ = listrec' refl (λ a _ hyp → trans (cong (_++_ a) hyp) (assocR {a}))
data Prefix (ls rs : List A) : Set where
prefixB : ls ≡ rs → Prefix ls rs
prefixL : {xs : List A} → ls ++ xs ≡ rs → Prefix ls rs
prefixR : {xs : List A} → rs ++ xs ≡ ls → Prefix ls rs
addToPrefix : {ls rs : List A} → (a : A) → Prefix ls rs → Prefix (a ∷ ls) (a ∷ rs)
addToPrefix a (prefixB refl) = prefixB refl
addToPrefix a (prefixL refl) = prefixL refl
addToPrefix a (prefixR refl) = prefixR refl
comparePrefix : {xs ys : List A} → (ls rs : List A) → ls ++ xs ≡ rs ++ ys → Prefix ls rs
comparePrefix [] [] eq = prefixB refl
comparePrefix [] rs eq = prefixL refl
comparePrefix ls [] eq = prefixR refl
comparePrefix (a ∷ ls) (_ ∷ rs) eq with ∷-inj eq
comparePrefix (a ∷ ls) (.a ∷ rs) eq | refl , eqls = addToPrefix a (comparePrefix ls rs eqls)
data Suffix (ls rs : List A) : Set where
suffixB : ls ≡ rs → Suffix ls rs
suffixL : (xs : List A) → xs ++ ls ≡ rs → Suffix ls rs
suffixR : (xs : List A) → xs ++ rs ≡ ls → Suffix ls rs
reverseAux : {bs cs : List A} → (as : List A) → reverse as ++ bs ≡ reverse cs → reverse bs ++ as ≡ cs
reverseAux {bs} as eq = reverseEq (trans2 (++reverse (reverse bs)) (cong (_++_ (reverse as)) revrev) eq)
compareSuffix : {xs ys : List A} → (ls rs : List A) → xs ++ ls ≡ ys ++ rs → Suffix ls rs
compareSuffix {xs} {ys} ls rs eq with comparePrefix (reverse ls) (reverse rs) (trans2 (sym (++reverse xs)) (cong reverse eq) (++reverse ys))
... | prefixB eq2 = suffixB (reverseEq eq2)
... | prefixL {xls} eq2 = suffixL (reverse xls) (reverseAux ls eq2)
... | prefixR {xrs} eq2 = suffixR (reverse xrs) (reverseAux rs eq2)
infix 3 _∈_
data _∈_ (a : A) : List A → Set where
hd : {as : List A} → a ∈ a ∷ as
tl : {b : A} → {as : List A} → a ∈ as → a ∈ b ∷ as
index : {a : A} → {as : List A} → a ∈ as → ℕ
index hd = O
index (tl el) = S (index el)
data Lookup (as : List A) : ℕ → Set where
inside : (a : A) → (el : a ∈ as) → Lookup as (index el)
outside : (n : ℕ) → Lookup as (length as + n)
_!_ : (as : List A) → (n : ℕ) → Lookup as n
[] ! n = outside n
(a ∷ as) ! O = inside a hd
(a ∷ as) ! S n with as ! n
(a ∷ as) ! S .(index el) | inside b el = inside b (tl el)
(a ∷ as) ! S .(length as + n) | outside n = outside n
open ListPropsAux public
lengthMap : {A B : Set} → {f : A → B} → (as : List A) → length (map f as) ≡ length as
lengthMap = listrec refl (cong S)
map++ : {A B : Set} → {f : A → B} → {as₂ : List A} → (as₁ : List A) → map f (as₁ ++ as₂) ≡ map f as₁ ++ map f as₂
map++ = listrec refl ∷-congL
mapmap : {A B C : Set} → {f : B → C} → {g : A → B} → (as : List A) → map f (map g as) ≡ map (f ∘ g) as
mapmap = listrec refl (∷-cong refl)