I’m working on a proof involving the scanr function in Agda and have encountered difficulties with branch reasoning. The proof seems straightforward, but implementing it is proving to be tricky. Here’s the code I’m working with:
open import Data.List using (List; []; _∷_; [_]; _++_; foldl; foldr; map; scanl; scanr)
open import Data.Bool using (Bool; true; false)
-contra : false ≡ true → ∀{ℓ} {P : Set ℓ} → P
-contra ()
is-empty : ∀{A : Set} → (xs : List A) → Bool
is-empty [] = true
is-empty (x ∷ xs) = false
scanr-not-empty : {A B : Set} (f : A → B → B) (e : B) (xs : List A) → is-empty (scanr f e xs) ≡ false
scanr-not-empty f e [] = refl
scanr-not-empty f e (x ∷ xs) with scanr f e xs in p'
... | [] = -contra (trans (sym (scanr-not-empty f e xs)) (cong is-empty p'))
... | y ∷ ys = refl
listFir : {A : Set} (xs : List A) → is-empty xs ≡ false → A
listFir (x ∷ xs) p = x
scanFir : {A B : Set} (f : A → B → B) (e : B) (xs : List A) → B
scanFir f e xs = listFir (scanr f e xs) (scanr-not-empty f e xs)
scanFi : {A B : Set} (f : A → B → B) (e : B) (x : A) (xs : List A) →
scanFir f e (x ∷ xs) ≡ f x (scanFir f e xs)
scanFi f e x xs = {!!}
And the standard library definition of scanr might be useful here:
scanr : (A → B → B) → B → List A → List B
scanr f e [] = e ∷ []
scanr f e (x ∷ xs) with scanr f e xs
... | [] = [] -- dead branch
... | y ∷ ys = f x y ∷ y ∷ ys
Could someone provide guidance on how to approach this proof, particularly how to handle the branches in the reasoning? I’m new to this, so thanks in advance for any pointers!
Quite an annoying problem indeed. Here's how to make it work:
Basically
scanr f e xsappears in bothscanr-not-empty f e xsandscanr-not-empty f e (x ∷ xs)and so you have to add those to thewith-expression in order forscanr f e xsto be rewritten in their types consistently with the rest of the expression. If these two aren't added to thewith-expression, then a fresh variablewis substituted forscanr f e xsin only half the places and you get a type error.You can learn more about this wrinkle here.