l3lab/ntp-mathlib huggingface dataset:
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · 

Proof state:
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
n : ℕ
h : n ≤ length (xs_hd :: xs_tl)
h' : n ≤ length xs_tl
⊢ length xs_tl + 1 - n = succ (length xs_tl - n)

Next tactic:
rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · 

Proof state:
case cons.inl
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
n : ℕ
h : n ≤ length (xs_hd :: xs_tl)
h' : n ≤ length xs_tl
⊢ n ≤ length (reverse xs_tl)

Next tactic:
rwa [length_reverse]
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · rwa [length_reverse]
  · 

Proof state:
case cons.inr
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
n : ℕ
h : n ≤ length (xs_hd :: xs_tl)
h' : n = length (xs_hd :: xs_tl)
⊢ take n (reverse xs_tl ++ [xs_hd]) = reverse (drop (length xs_tl + 1 - n) (xs_hd :: xs_tl))

Next tactic:
subst h'
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · rwa [length_reverse]
  · subst h'
    

Proof state:
case cons.inr
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
h : length (xs_hd :: xs_tl) ≤ length (xs_hd :: xs_tl)
⊢ take (length (xs_hd :: xs_tl)) (reverse xs_tl ++ [xs_hd]) =
    reverse (drop (length xs_tl + 1 - length (xs_hd :: xs_tl)) (xs_hd :: xs_tl))

Next tactic:
rw [length, tsub_self, drop]
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · rwa [length_reverse]
  · subst h'
    rw [length, tsub_self, drop]
    

Proof state:
case cons.inr
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
h : length (xs_hd :: xs_tl) ≤ length (xs_hd :: xs_tl)
⊢ take (length xs_tl + 1) (reverse xs_tl ++ [xs_hd]) = reverse (xs_hd :: xs_tl)

Next tactic:
suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by
      rw [this, take_length, reverse_cons]
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · rwa [length_reverse]
  · subst h'
    rw [length, tsub_self, drop]
    suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by
      

Proof state:
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
h : length (xs_hd :: xs_tl) ≤ length (xs_hd :: xs_tl)
this : length xs_tl + 1 = length (reverse xs_tl ++ [xs_hd])
⊢ take (length xs_tl + 1) (reverse xs_tl ++ [xs_hd]) = reverse (xs_hd :: xs_tl)

Next tactic:
rw [this, take_length, reverse_cons]
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · rwa [length_reverse]
  · subst h'
    rw [length, tsub_self, drop]
    suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by
      rw [this, take_length, reverse_cons]
    

Proof state:
case cons.inr
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
h : length (xs_hd :: xs_tl) ≤ length (xs_hd :: xs_tl)
⊢ length xs_tl + 1 = length (reverse xs_tl ++ [xs_hd])

Next tactic:
rw [length_append, length_reverse]
theorem reverse_take {α} {xs : List α} (n : ℕ) (h : n ≤ xs.length) :
    xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
  induction' xs with xs_hd xs_tl xs_ih generalizing n <;>
    simp only [reverse_cons, drop, reverse_nil, zero_tsub, length, take_nil]
  cases' h.lt_or_eq_dec with h' h'
  · replace h' := le_of_succ_le_succ h'
    rw [take_append_of_le_length, xs_ih _ h']
    rw [show xs_tl.length + 1 - n = succ (xs_tl.length - n) from _, drop]
    · rwa [succ_eq_add_one, ← @tsub_add_eq_add_tsub]
    · rwa [length_reverse]
  · subst h'
    rw [length, tsub_self, drop]
    suffices xs_tl.length + 1 = (xs_tl.reverse ++ [xs_hd]).length by
      rw [this, take_length, reverse_cons]
    rw [length_append, length_reverse]
    

Proof state:
case cons.inr
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
xs_hd : α
xs_tl : List α
xs_ih : ∀ (n : ℕ), n ≤ length xs_tl → take n (reverse xs_tl) = reverse (drop (length xs_tl - n) xs_tl)
h : length (xs_hd :: xs_tl) ≤ length (xs_hd :: xs_tl)
⊢ length xs_tl + 1 = length xs_tl + length [xs_hd]

Next tactic:
rfl
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
n : ℕ
a : α
⊢ set l n a = [] ↔ l = []

Next tactic:
cases l
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  cases l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
n : ℕ
a : α
⊢ set [] n a = [] ↔ [] = []

Next tactic:
cases n
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  cases l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
n : ℕ
a head✝ : α
tail✝ : List α
⊢ set (head✝ :: tail✝) n a = [] ↔ head✝ :: tail✝ = []

Next tactic:
cases n
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  cases l <;> cases n <;> 

Proof state:
case nil.zero
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
⊢ set [] zero a = [] ↔ [] = []

Next tactic:
simp only [set]
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  cases l <;> cases n <;> 

Proof state:
case nil.succ
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n✝ : ℕ
⊢ set [] (succ n✝) a = [] ↔ [] = []

Next tactic:
simp only [set]
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  cases l <;> cases n <;> 

Proof state:
case cons.zero
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
⊢ set (head✝ :: tail✝) zero a = [] ↔ head✝ :: tail✝ = []

Next tactic:
simp only [set]
@[simp]
theorem set_eq_nil (l : List α) (n : ℕ) (a : α) : l.set n a = [] ↔ l = [] := by
  cases l <;> cases n <;> 

Proof state:
case cons.succ
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
n✝ : ℕ
⊢ set (head✝ :: tail✝) (succ n✝) a = [] ↔ head✝ :: tail✝ = []

Next tactic:
simp only [set]
@[simp]
theorem takeI_left (l₁ l₂ : List α) : takeI (length l₁) (l₁ ++ l₂) = l₁ :=
  (takeI_eq_take (by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
inst✝ : Inhabited α
l₁ l₂ : List α
⊢ length l₁ ≤ length (l₁ ++ l₂)

Next tactic:
simp only [length_append, Nat.le_add_right]
theorem takeI_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : takeI n (l₁ ++ l₂) = l₁ := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
inst✝ : Inhabited α
l₁ l₂ : List α
n : ℕ
h : length l₁ = n
⊢ takeI n (l₁ ++ l₂) = l₁

Next tactic:
rw [← h]
theorem takeI_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : takeI n (l₁ ++ l₂) = l₁ := by
  rw [← h]; 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
inst✝ : Inhabited α
l₁ l₂ : List α
n : ℕ
h : length l₁ = n
⊢ takeI (length l₁) (l₁ ++ l₂) = l₁

Next tactic:
apply takeI_left
@[simp]
theorem takeD_left (l₁ l₂ : List α) (a : α) : takeD (length l₁) (l₁ ++ l₂) a = l₁ :=
  (takeD_eq_take a (by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ l₁ l₂ : List α
a : α
⊢ length l₁ ≤ length (l₁ ++ l₂)

Next tactic:
simp only [length_append, Nat.le_add_right]
theorem takeD_left' {l₁ l₂ : List α} {n} {a} (h : length l₁ = n) : takeD n (l₁ ++ l₂) a = l₁ :=
  by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ l₁ l₂ : List α
n : ℕ
a : α
h : length l₁ = n
⊢ takeD n (l₁ ++ l₂) a = l₁

Next tactic:
rw [← h]
theorem takeD_left' {l₁ l₂ : List α} {n} {a} (h : length l₁ = n) : takeD n (l₁ ++ l₂) a = l₁ :=
  by rw [← h]; 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ l₁ l₂ : List α
n : ℕ
a : α
h : length l₁ = n
⊢ takeD (length l₁) (l₁ ++ l₂) a = l₁

Next tactic:
apply takeD_left
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → α
a : α
l : List β
H : ∀ (a : α) (b : β), b ∈ l → f a b = g a b
⊢ foldl f a l = foldl g a l

Next tactic:
induction l generalizing a with
  | nil => rfl
  | cons hd tl ih =>
    unfold foldl
    rw [ih _ fun a b bin => H a b <| mem_cons_of_mem _ bin, H a hd (mem_cons_self _ _)]
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  induction l generalizing a with
  

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → α
a : α
H : ∀ (a : α) (b : β), b ∈ [] → f a b = g a b
⊢ foldl f a [] = foldl g a []

Next tactic:
| nil => rfl
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  induction l generalizing a with
  | nil => 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → α
a : α
H : ∀ (a : α) (b : β), b ∈ [] → f a b = g a b
⊢ foldl f a [] = foldl g a []

Next tactic:
rfl
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  induction l generalizing a with
  | nil => rfl
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → α
hd : β
tl : List β
ih : ∀ (a : α), (∀ (a : α) (b : β), b ∈ tl → f a b = g a b) → foldl f a tl = foldl g a tl
a : α
H : ∀ (a : α) (b : β), b ∈ hd :: tl → f a b = g a b
⊢ foldl f a (hd :: tl) = foldl g a (hd :: tl)

Next tactic:
| cons hd tl ih =>
    unfold foldl
    rw [ih _ fun a b bin => H a b <| mem_cons_of_mem _ bin, H a hd (mem_cons_self _ _)]
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  induction l generalizing a with
  | nil => rfl
  | cons hd tl ih =>
    

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → α
hd : β
tl : List β
ih : ∀ (a : α), (∀ (a : α) (b : β), b ∈ tl → f a b = g a b) → foldl f a tl = foldl g a tl
a : α
H : ∀ (a : α) (b : β), b ∈ hd :: tl → f a b = g a b
⊢ foldl f a (hd :: tl) = foldl g a (hd :: tl)

Next tactic:
unfold foldl
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  induction l generalizing a with
  | nil => rfl
  | cons hd tl ih =>
    unfold foldl
    

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → α
hd : β
tl : List β
ih : ∀ (a : α), (∀ (a : α) (b : β), b ∈ tl → f a b = g a b) → foldl f a tl = foldl g a tl
a : α
H : ∀ (a : α) (b : β), b ∈ hd :: tl → f a b = g a b
⊢ foldl f (f a hd) tl = foldl g (g a hd) tl

Next tactic:
rw [ih _ fun a b bin => H a b <| mem_cons_of_mem _ bin, H a hd (mem_cons_self _ _)]
theorem foldr_ext (f g : α → β → β) (b : β) {l : List α} (H : ∀ a ∈ l, ∀ b : β, f a b = g a b) :
    foldr f b l = foldr g b l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → β
b : β
l : List α
H : ∀ (a : α), a ∈ l → ∀ (b : β), f a b = g a b
⊢ foldr f b l = foldr g b l

Next tactic:
induction' l with hd tl ih
theorem foldr_ext (f g : α → β → β) (b : β) {l : List α} (H : ∀ a ∈ l, ∀ b : β, f a b = g a b) :
    foldr f b l = foldr g b l := by
  induction' l with hd tl ih; · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → β
b : β
H : ∀ (a : α), a ∈ [] → ∀ (b : β), f a b = g a b
⊢ foldr f b [] = foldr g b []

Next tactic:
rfl
theorem foldr_ext (f g : α → β → β) (b : β) {l : List α} (H : ∀ a ∈ l, ∀ b : β, f a b = g a b) :
    foldr f b l = foldr g b l := by
  induction' l with hd tl ih; · rfl
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → β
b : β
hd : α
tl : List α
ih : (∀ (a : α), a ∈ tl → ∀ (b : β), f a b = g a b) → foldr f b tl = foldr g b tl
H : ∀ (a : α), a ∈ hd :: tl → ∀ (b : β), f a b = g a b
⊢ foldr f b (hd :: tl) = foldr g b (hd :: tl)

Next tactic:
simp only [mem_cons, or_imp, forall_and, forall_eq] at H
theorem foldr_ext (f g : α → β → β) (b : β) {l : List α} (H : ∀ a ∈ l, ∀ b : β, f a b = g a b) :
    foldr f b l = foldr g b l := by
  induction' l with hd tl ih; · rfl
  simp only [mem_cons, or_imp, forall_and, forall_eq] at H
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → β → β
b : β
hd : α
tl : List α
ih : (∀ (a : α), a ∈ tl → ∀ (b : β), f a b = g a b) → foldr f b tl = foldr g b tl
H : (∀ (b : β), f hd b = g hd b) ∧ ∀ (x : α), x ∈ tl → ∀ (b : β), f x b = g x b
⊢ foldr f b (hd :: tl) = foldr g b (hd :: tl)

Next tactic:
simp only [foldr, ih H.2, H.1]
theorem foldl_concat
    (f : β → α → β) (b : β) (x : α) (xs : List α) :
    List.foldl f b (xs ++ [x]) = f (List.foldl f b xs) x := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : β → α → β
b : β
x : α
xs : List α
⊢ foldl f b (xs ++ [x]) = f (foldl f b xs) x

Next tactic:
simp only [List.foldl_append, List.foldl]
theorem foldr_concat
    (f : α → β → β) (b : β) (x : α) (xs : List α) :
    List.foldr f b (xs ++ [x]) = (List.foldr f (f x b) xs) := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β → β
b : β
x : α
xs : List α
⊢ foldr f b (xs ++ [x]) = foldr f (f x b) xs

Next tactic:
simp only [List.foldr_append, List.foldr]
theorem foldl_fixed' {f : α → β → α} {a : α} (hf : ∀ b, f a b = a) : ∀ l : List β, foldl f a l = a
  | [] => rfl
  | b :: l => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β → α
a : α
hf : ∀ (b : β), f a b = a
b : β
l : List β
⊢ foldl f a (b :: l) = a

Next tactic:
rw [foldl_cons, hf b, foldl_fixed' hf l]
theorem foldr_fixed' {f : α → β → β} {b : β} (hf : ∀ a, f a b = b) : ∀ l : List α, foldr f b l = b
  | [] => rfl
  | a :: l => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β → β
b : β
hf : ∀ (a : α), f a b = b
a : α
l : List α
⊢ foldr f b (a :: l) = b

Next tactic:
rw [foldr_cons, foldr_fixed' hf l, hf a]
@[simp]
theorem foldl_join (f : α → β → α) :
    ∀ (a : α) (L : List (List β)), foldl f a (join L) = foldl (foldl f) a L
  | a, [] => rfl
  | a, l :: L => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β → α
a : α
l : List β
L : List (List β)
⊢ foldl f a (join (l :: L)) = foldl (foldl f) a (l :: L)

Next tactic:
simp only [join, foldl_append, foldl_cons, foldl_join f (foldl f a l) L]
@[simp]
theorem foldr_join (f : α → β → β) :
    ∀ (b : β) (L : List (List α)), foldr f b (join L) = foldr (fun l b => foldr f b l) b L
  | a, [] => rfl
  | a, l :: L => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β → β
a : β
l : List α
L : List (List α)
⊢ foldr f a (join (l :: L)) = foldr (fun l b => foldr f b l) a (l :: L)

Next tactic:
simp only [join, foldr_append, foldr_join f a L, foldr_cons]
theorem foldr_eta : ∀ l : List α, foldr cons [] l = l :=
  by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
⊢ ∀ (l : List α), foldr cons [] l = l

Next tactic:
simp only [foldr_self_append, append_nil, forall_const]
@[simp]
theorem reverse_foldl {l : List α} : reverse (foldl (fun t h => h :: t) [] l) = l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
⊢ reverse (foldl (fun t h => h :: t) [] l) = l

Next tactic:
rw [← foldr_reverse]
@[simp]
theorem reverse_foldl {l : List α} : reverse (foldl (fun t h => h :: t) [] l) = l := by
  rw [← foldr_reverse]; 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
⊢ reverse (foldr (fun h t => h :: t) [] (reverse l)) = l

Next tactic:
simp only [foldr_self_append, append_nil, reverse_reverse]
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    List.foldl f' (g a) (l.map g) = g (List.foldl f a l) := by
  

Proof state:
ι : Type u_1
α✝ : Type u
β✝ : Type v
γ : Type w
l₁ l₂ : List α✝
α β : Type u
g : α → β
f : α → α → α
f' : β → β → β
a : α
l : List α
h : ∀ (x y : α), f' (g x) (g y) = g (f x y)
⊢ foldl f' (g a) (map g l) = g (foldl f a l)

Next tactic:
induction l generalizing a
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    List.foldl f' (g a) (l.map g) = g (List.foldl f a l) := by
  induction l generalizing a
  · 

Proof state:
case nil
ι : Type u_1
α✝ : Type u
β✝ : Type v
γ : Type w
l₁ l₂ : List α✝
α β : Type u
g : α → β
f : α → α → α
f' : β → β → β
h : ∀ (x y : α), f' (g x) (g y) = g (f x y)
a : α
⊢ foldl f' (g a) (map g []) = g (foldl f a [])

Next tactic:
simp
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    List.foldl f' (g a) (l.map g) = g (List.foldl f a l) := by
  induction l generalizing a
  · simp
  · 

Proof state:
case cons
ι : Type u_1
α✝ : Type u
β✝ : Type v
γ : Type w
l₁ l₂ : List α✝
α β : Type u
g : α → β
f : α → α → α
f' : β → β → β
h : ∀ (x y : α), f' (g x) (g y) = g (f x y)
head✝ : α
tail✝ : List α
tail_ih✝ : ∀ (a : α), foldl f' (g a) (map g tail✝) = g (foldl f a tail✝)
a : α
⊢ foldl f' (g a) (map g (head✝ :: tail✝)) = g (foldl f a (head✝ :: tail✝))

Next tactic:
simp [*, h]
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    List.foldr f' (g a) (l.map g) = g (List.foldr f a l) := by
  

Proof state:
ι : Type u_1
α✝ : Type u
β✝ : Type v
γ : Type w
l₁ l₂ : List α✝
α β : Type u
g : α → β
f : α → α → α
f' : β → β → β
a : α
l : List α
h : ∀ (x y : α), f' (g x) (g y) = g (f x y)
⊢ foldr f' (g a) (map g l) = g (foldr f a l)

Next tactic:
induction l generalizing a
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    List.foldr f' (g a) (l.map g) = g (List.foldr f a l) := by
  induction l generalizing a
  · 

Proof state:
case nil
ι : Type u_1
α✝ : Type u
β✝ : Type v
γ : Type w
l₁ l₂ : List α✝
α β : Type u
g : α → β
f : α → α → α
f' : β → β → β
h : ∀ (x y : α), f' (g x) (g y) = g (f x y)
a : α
⊢ foldr f' (g a) (map g []) = g (foldr f a [])

Next tactic:
simp
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    List.foldr f' (g a) (l.map g) = g (List.foldr f a l) := by
  induction l generalizing a
  · simp
  · 

Proof state:
case cons
ι : Type u_1
α✝ : Type u
β✝ : Type v
γ : Type w
l₁ l₂ : List α✝
α β : Type u
g : α → β
f : α → α → α
f' : β → β → β
h : ∀ (x y : α), f' (g x) (g y) = g (f x y)
head✝ : α
tail✝ : List α
tail_ih✝ : ∀ (a : α), foldr f' (g a) (map g tail✝) = g (foldr f a tail✝)
a : α
⊢ foldr f' (g a) (map g (head✝ :: tail✝)) = g (foldr f a (head✝ :: tail✝))

Next tactic:
simp [*, h]
theorem foldl_hom₂ (l : List ι) (f : α → β → γ) (op₁ : α → ι → α) (op₂ : β → ι → β)
    (op₃ : γ → ι → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ a i) (op₂ b i) = op₃ (f a b) i) :
    foldl op₃ (f a b) l = f (foldl op₁ a l) (foldl op₂ b l) :=
  Eq.symm <| by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
l : List ι
f : α → β → γ
op₁ : α → ι → α
op₂ : β → ι → β
op₃ : γ → ι → γ
a : α
b : β
h : ∀ (a : α) (b : β) (i : ι), f (op₁ a i) (op₂ b i) = op₃ (f a b) i
⊢ f (foldl op₁ a l) (foldl op₂ b l) = foldl op₃ (f a b) l

Next tactic:
revert a b
theorem foldl_hom₂ (l : List ι) (f : α → β → γ) (op₁ : α → ι → α) (op₂ : β → ι → β)
    (op₃ : γ → ι → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ a i) (op₂ b i) = op₃ (f a b) i) :
    foldl op₃ (f a b) l = f (foldl op₁ a l) (foldl op₂ b l) :=
  Eq.symm <| by
    revert a b
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
l : List ι
f : α → β → γ
op₁ : α → ι → α
op₂ : β → ι → β
op₃ : γ → ι → γ
h : ∀ (a : α) (b : β) (i : ι), f (op₁ a i) (op₂ b i) = op₃ (f a b) i
⊢ ∀ (a : α) (b : β), f (foldl op₁ a l) (foldl op₂ b l) = foldl op₃ (f a b) l

Next tactic:
induction l <;> intros <;> [rfl; simp only [*, foldl]]