{-# OPTIONS --cubical --safe #-}
module Data.List.Properties where
open import Data.List
open import Prelude
open import Data.Fin
open import Strict.Properties
reverse : List A → List A
reverse = foldl (flip _∷_) []
foldl-by-r : (B → A → B) → B → List A → B
foldl-by-r f b xs = foldr (λ x k xs → k (f xs x)) id xs b
map-length : (f : A → B) (xs : List A)
→ length xs ≡ length (map f xs)
map-length f [] _ = zero
map-length f (x ∷ xs) i = suc (map-length f xs i)
map-ind : (f : A → B) (xs : List A)
→ PathP (λ i → Fin (map-length f xs i) → B) (f ∘ (xs !_)) (map f xs !_)
map-ind f [] i ()
map-ind f (x ∷ xs) i f0 = f x
map-ind f (x ∷ xs) i (fs n) = map-ind f xs i n
tab-length : ∀ n (f : Fin n → A) → length (tabulate n f) ≡ n
tab-length zero f _ = zero
tab-length (suc n) f i = suc (tab-length n (f ∘ fs) i)
tab-distrib : ∀ n (f : Fin n → A) m → ∃ i × (f i ≡ tabulate n f ! m)
tab-distrib (suc n) f f0 = f0 , refl
tab-distrib (suc n) f (fs m) = let i , p = tab-distrib n (f ∘ fs) m in fs i , p
tab-id : ∀ n (f : Fin n → A) → PathP (λ i → Fin (tab-length n f i) → A) (_!_ (tabulate n f)) f
tab-id zero f _ ()
tab-id (suc n) f i f0 = f f0
tab-id (suc n) f i (fs m) = tab-id n (f ∘ fs) i m
list-elim : ∀ {p} (P : List A → Type p) →
(∀ x xs → P xs → P (x ∷ xs)) →
(P []) →
∀ xs → P xs
list-elim P f b [] = b
list-elim P f b (x ∷ xs) = f x xs (list-elim P f b xs)
foldr-universal : ∀ (h : List B → A) f e
→ (h [] ≡ e)
→ (∀ x xs → h (x ∷ xs) ≡ f x (h xs))
→ ∀ xs → h xs ≡ foldr f e xs
foldr-universal h f e base step [] = base
foldr-universal h f e base step (x ∷ xs) =
step x xs ; cong (f x) (foldr-universal h f e base step xs)
foldr-id : (xs : List A) → xs ≡ foldr _∷_ [] xs
foldr-id = foldr-universal id _∷_ [] refl (λ _ _ → refl)
foldr-fusion : ∀ (f : C → A) {_⊕_ : B → C → C} {_⊗_ : B → A → A} e
→ (∀ x y → f (x ⊕ y) ≡ x ⊗ f y)
→ ∀ xs → f (foldr _⊕_ e xs) ≡ foldr _⊗_ (f e) xs
foldr-fusion h {f} {g} e fuse =
foldr-universal (h ∘ foldr f e) g (h e) refl (λ x xs → fuse x (foldr f e xs))
foldr-++ : (f : A → B → B) (b : B) (xs ys : List A)
→ foldr f b (xs ++ ys) ≡ foldr f (foldr f b ys) xs
foldr-++ f b xs ys = foldr-fusion (foldr f b) ys (λ _ _ → refl) xs
foldl-is-foldr : (f : B → A → B) (z : B) (xs : List A) →
foldl f z xs ≡ foldl-by-r f z xs
foldl-is-foldr f z xs =
cong (_$ z) (foldr-universal (flip (foldl f)) (λ x k xs → k (f xs x)) id refl (λ x xs → refl) xs)
foldl-fusion : ∀ (f : C → A) {_⊕_ : C → B → C} {_⊗_ : A → B → A} e →
(∀ x y → f (x ⊕ y) ≡ f x ⊗ y) →
∀ xs → f (foldl _⊕_ e xs) ≡ foldl _⊗_ (f e) xs
foldl-fusion h {f} {g} e fuse [] = refl
foldl-fusion h {f} {g} e fuse (x ∷ xs) =
foldl-fusion h (f e x) fuse xs ; cong (flip (foldl g) xs) (fuse e x)
open import Path.Reasoning
module _ {A : Type a} {B : Type b} where
foldl-++ : (f : B → A → B) (b : B) (xs ys : List A)
→ foldl f b (xs ++ ys) ≡ foldl f (foldl f b xs) ys
foldl-++ f b xs ys =
foldl f b (xs ++ ys) ≡⟨ foldl-is-foldr f b (xs ++ ys) ⟩
foldl-by-r f b (xs ++ ys) ≡⟨ cong (_$ b) (foldr-++ (λ x k b → k (f b x)) id xs ys) ⟩
foldr (λ x k b → k (f b x)) (foldr (λ x k b → k (f b x)) id ys) xs b ≡˘⟨ cong (λ e → foldr (λ x k b → k (f b x)) e xs b) (funExt λ b → foldl-is-foldr f b ys) ⟩
foldr (λ x k b → k (f b x)) (flip (foldl f) ys) xs b ≡˘⟨ cong′ {A = B → B} (_$ b) (foldr-universal (λ xs b → foldl f (foldl f b xs) ys) (λ x k b → k (f b x)) (flip (foldl f) ys) refl (λ _ _ → refl) xs ) ⟩
foldl f (foldl f b xs) ys ∎
foldl-by-r-cons : (A → B → B) → A → (B → B) → B → B
foldl-by-r-cons f x k xs = k (f x xs)
foldr-reverse : (f : A → B → B) (b : B) (xs : List A)
→ foldr f b (reverse xs) ≡ foldl (flip f) b xs
foldr-reverse f b = foldl-fusion (foldr f b) [] (λ _ _ → refl)
module _ {A : Type a} where
reverse-reverse : (xs : List A) → reverse (reverse xs) ≡ xs
reverse-reverse xs = foldl-is-foldr (flip _∷_) [] (reverse xs)
; cong (_$ [])
( foldr-reverse (foldl-by-r-cons _∷_) id xs
; foldl-is-foldr (flip (foldl-by-r-cons _∷_)) id xs
; cong′ (_$ id) (sym (foldr-universal (λ xs k a → k (foldr _∷_ a xs)) (foldl-by-r-cons (foldl-by-r-cons _∷_)) id refl (λ x xs → refl) xs))
)
; sym (foldr-id xs)
++-assoc : (xs ys zs : List A) → (xs ++ ys) ++ zs ≡ xs ++ (ys ++ zs)
++-assoc xs ys zs = foldr-fusion (_++ zs) ys (λ _ _ → refl) xs
map-fusion : ∀ f (b : C) (g : A → B) xs → foldr f b (map g xs) ≡ foldr (f ∘ g) b xs
map-fusion f b g = foldr-fusion (foldr f b) [] λ _ _ → refl
++-idʳ : (xs : List A) → xs ++ [] ≡ xs
++-idʳ [] = refl
++-idʳ (x ∷ xs) = cong (x ∷_) (++-idʳ xs)
open import Function.Injective
∷-inj : (x : A) → Injective (x ∷_)
∷-inj x xs ys = cong λ where [] → []
(_ ∷ zs) → zs
++-inj : (xs : List A) → Injective (xs ++_)
++-inj [] ys zs ys≡zs = ys≡zs
++-inj (x ∷ xs) ys zs ys≡zs = ++-inj xs ys zs (∷-inj x (xs ++ ys) (xs ++ zs) ys≡zs)
open import Algebra
module _ {𝑆 : Type b} (mon : Monoid 𝑆) where
open Monoid mon
module _ (f : A → 𝑆) where
monStepL : 𝑆 → A → 𝑆
monStepL xs x = xs ∙ f x
{-# INLINE monStepL #-}
foldMapL : List A → 𝑆
foldMapL = foldl monStepL ε
foldMapLStep : ∀ x xs → f x ∙ foldMapL xs ≡ foldMapL (x ∷ xs)
foldMapLStep x xs = foldl-fusion (f x ∙_) ε (λ y z → sym (assoc (f x) y (f z))) xs ; cong (flip (foldl monStepL) xs) (∙ε (f x) ; sym (ε∙ (f x)))
foldl-foldr-monoid : (xs : List A) → foldMapL xs ≡ foldr (_∙_ ∘ f) ε xs
foldl-foldr-monoid = foldr-universal _ (_∙_ ∘ f) ε refl λ x xs → sym (foldMapLStep x xs)
module _ (A : Type a) where
listMonoid : Monoid (List A)
listMonoid .Monoid._∙_ = _++_
listMonoid .Monoid.ε = []
listMonoid .Monoid.assoc = ++-assoc
listMonoid .Monoid.ε∙ _ = refl
listMonoid .Monoid.∙ε = ++-idʳ
listFunctor : Functor {ℓ₁ = a} List
listFunctor .Functor.map = map
listFunctor .Functor.map-id = funExt (sym ∘ foldr-id)
listFunctor .Functor.map-comp f g = funExt λ xs → sym (map-fusion _ _ _ xs)
foldl′-foldl : (f : B → A → B) (z : B) (xs : List A) → foldl′ f z xs ≡ foldl f z xs
foldl′-foldl f z [] = refl
foldl′-foldl f z (x ∷ xs) = $!-≡ (λ y → foldl′ f y xs) (f z x) ; foldl′-foldl f (f z x) xs
foldr′-foldr : (f : A → B → B) (z : B) (xs : List A) → foldr′ f z xs ≡ foldr f z xs
foldr′-foldr f z [] = refl
foldr′-foldr f z (x ∷ xs) = $!-≡ (f x) (foldr′ f z xs) ; cong (f x) (foldr′-foldr f z xs)
is-empty : List A → Bool
is-empty [] = true
is-empty (_ ∷ _) = false
NonEmpty : List A → Type
NonEmpty = T ∘ not ∘ is-empty
open import Data.Maybe.Properties
foldrMay-nonEmpty : (f : A → A → A) (xs : List A) → NonEmpty xs → IsJust (foldrMay f xs)
foldrMay-nonEmpty f (x ∷ xs) _ = tt
foldr1 : (A → A → A) → (xs : List A) → ⦃ NonEmpty xs ⦄ → A
foldr1 f xs ⦃ xsne ⦄ = fromJust (foldrMay f xs)
where instance _ = foldrMay-nonEmpty f xs xsne