{-# OPTIONS --cubical --safe #-}
module Data.Nat.Fold where
open import Prelude
open import Data.Nat
foldr-ℕ : (A → A) → A → ℕ → A
foldr-ℕ f b zero = b
foldr-ℕ f b (suc n) = f (foldr-ℕ f b n)
foldr-ℕ-universal : ∀ (h : ℕ → A) f x →
(h zero ≡ x) →
(∀ n → h (suc n) ≡ f (h n)) →
∀ n → h n ≡ foldr-ℕ f x n
foldr-ℕ-universal h f x base step zero = base
foldr-ℕ-universal h f x base step (suc n) = step n ; cong f (foldr-ℕ-universal h f x base step n)
foldl-ℕ-go : (A → A) → ℕ → A → A
foldl-ℕ-go f zero x = x
foldl-ℕ-go f (suc n) x = foldl-ℕ-go f n $! f x
foldl-ℕ : (A → A) → A → ℕ → A
foldl-ℕ f x n = foldl-ℕ-go f n $! x
{-# INLINE foldl-ℕ #-}
f-comm : ∀ (f : A → A) x n → f (foldr-ℕ f x n) ≡ foldr-ℕ f (f x) n
f-comm f x zero i = f x
f-comm f x (suc n) i = f (f-comm f x n i)
foldl-ℕ-foldr : ∀ f (x : A) n → foldr-ℕ f x n ≡ foldl-ℕ f x n
foldl-ℕ-foldr f x zero = sym ($!-≡ (foldl-ℕ-go f zero) x)
foldl-ℕ-foldr f x (suc n) = f-comm f x n ; foldl-ℕ-foldr f (f x) n ; sym ($!-≡ (foldl-ℕ-go f (suc n)) x)
foldl-ℕ-universal : ∀ (h : ℕ → A) f x →
(h zero ≡ x) →
(∀ n → h (suc n) ≡ f (h n)) →
∀ n → h n ≡ foldl-ℕ f x n
foldl-ℕ-universal h f x base step n = foldr-ℕ-universal h f x base step n ; foldl-ℕ-foldr f x n