{-# OPTIONS --cubical --safe #-}
module Data.Bits.Fold where
open import Data.Bits
open import Strict
open import Prelude
module _ {a} {A : Type a} (zer : A → A) (one : A → A) (base : A) where
foldr-bits : Bits → A
foldr-bits [] = base
foldr-bits (0∷ xs) = zer (foldr-bits xs)
foldr-bits (1∷ xs) = one (foldr-bits xs)
foldr-universal : ∀ (h : Bits → A) z o e →
(h [] ≡ e) →
(∀ xs → h (0∷ xs) ≡ z (h xs)) →
(∀ xs → h (1∷ xs) ≡ o (h xs)) →
∀ xs → h xs ≡ foldr-bits z o e xs
foldr-universal h z o e base zer one [] = base
foldr-universal h z o e base zer one (0∷ xs) = zer xs ; cong z (foldr-universal h z o e base zer one xs)
foldr-universal h z o e base zer one (1∷ xs) = one xs ; cong o (foldr-universal h z o e base zer one xs)
module _ {a} {A : Type a} (zer : A → A) (one : A → A) where
foldl-go : Bits → A → A
foldl-go [] base = base
foldl-go (0∷ xs) base = foldl-go xs $! zer base
foldl-go (1∷ xs) base = foldl-go xs $! one base
foldl-bits : A → Bits → A
foldl-bits = λ base xs → foldl-go xs $! base
{-# INLINE foldl-bits #-}
foldl-universal : ∀ (h : Bits → A → A) z o e →
(∀ xs bs → h (0∷ xs) bs ≡ h xs (z bs)) →
(∀ xs bs → h (1∷ xs) bs ≡ h xs (o bs)) →
(∀ bs → h [] bs ≡ bs) →
∀ xs → h xs e ≡ foldl-bits z o e xs
foldl-universal h z o e zer one bs [] = bs e ; sym ($!-≡ (foldl-go z o []) e)
foldl-universal h z o e zer one bs (0∷ xs) = zer xs e ; foldl-universal h z o (z e) zer one bs xs ; sym ($!-≡ (foldl-go z o (0∷ xs)) e)
foldl-universal h z o e zer one bs (1∷ xs) = one xs e ; foldl-universal h z o (o e) zer one bs xs ; sym ($!-≡ (foldl-go z o (1∷ xs)) e)