l3lab/ntp-mathlib huggingface dataset:
theorem forall_zipWith {f : α → β → γ} {p : γ → Prop} :
    ∀ {l₁ : List α} {l₂ : List β}, length l₁ = length l₂ →
      (Forall p (zipWith f l₁ l₂) ↔ Forall₂ (fun x y => p (f x y)) l₁ l₂)
  | [], [], _ => by simp
  | a :: l₁, b :: l₂, h => by
    

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
p : γ → Prop
a : α
l₁ : List α
b : β
l₂ : List β
h : length (a :: l₁) = length (b :: l₂)
⊢ Forall p (zipWith f (a :: l₁) (b :: l₂)) ↔ Forall₂ (fun x y => p (f x y)) (a :: l₁) (b :: l₂)

Next tactic:
simp only [length_cons, succ_inj'] at h
theorem forall_zipWith {f : α → β → γ} {p : γ → Prop} :
    ∀ {l₁ : List α} {l₂ : List β}, length l₁ = length l₂ →
      (Forall p (zipWith f l₁ l₂) ↔ Forall₂ (fun x y => p (f x y)) l₁ l₂)
  | [], [], _ => by simp
  | a :: l₁, b :: l₂, h => by
    simp only [length_cons, succ_inj'] at h
    

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
p : γ → Prop
a : α
l₁ : List α
b : β
l₂ : List β
h : length l₁ = length l₂
⊢ Forall p (zipWith f (a :: l₁) (b :: l₂)) ↔ Forall₂ (fun x y => p (f x y)) (a :: l₁) (b :: l₂)

Next tactic:
simp [forall_zipWith h]
theorem lt_length_left_of_zipWith {f : α → β → γ} {i : ℕ} {l : List α} {l' : List β}
    (h : i < (zipWith f l l').length) : i < l.length := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
i : ℕ
l : List α
l' : List β
h : i < length (zipWith f l l')
⊢ i < length l

Next tactic:
rw [length_zipWith, lt_min_iff] at h
theorem lt_length_left_of_zipWith {f : α → β → γ} {i : ℕ} {l : List α} {l' : List β}
    (h : i < (zipWith f l l').length) : i < l.length := by
  rw [length_zipWith, lt_min_iff] at h
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
i : ℕ
l : List α
l' : List β
h : i < length l ∧ i < length l'
⊢ i < length l

Next tactic:
exact h.left
theorem lt_length_right_of_zipWith {f : α → β → γ} {i : ℕ} {l : List α} {l' : List β}
    (h : i < (zipWith f l l').length) : i < l'.length := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
i : ℕ
l : List α
l' : List β
h : i < length (zipWith f l l')
⊢ i < length l'

Next tactic:
rw [length_zipWith, lt_min_iff] at h
theorem lt_length_right_of_zipWith {f : α → β → γ} {i : ℕ} {l : List α} {l' : List β}
    (h : i < (zipWith f l l').length) : i < l'.length := by
  rw [length_zipWith, lt_min_iff] at h
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
i : ℕ
l : List α
l' : List β
h : i < length l ∧ i < length l'
⊢ i < length l'

Next tactic:
exact h.right
theorem mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂
  | _ :: l₁, _ :: l₂, h => by
    

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
b : β
head✝¹ : α
l₁ : List α
head✝ : β
l₂ : List β
h : (a, b) ∈ zip (head✝¹ :: l₁) (head✝ :: l₂)
⊢ a ∈ head✝¹ :: l₁ ∧ b ∈ head✝ :: l₂

Next tactic:
cases' h with _ _ _ h
theorem mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂
  | _ :: l₁, _ :: l₂, h => by
    cases' h with _ _ _ h
    · 

Proof state:
case head
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
b : β
l₁ : List α
l₂ : List β
⊢ a ∈ a :: l₁ ∧ b ∈ b :: l₂

Next tactic:
simp
theorem mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂
  | _ :: l₁, _ :: l₂, h => by
    cases' h with _ _ _ h
    · simp
    · 

Proof state:
case tail
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
b : β
head✝¹ : α
l₁ : List α
head✝ : β
l₂ : List β
h : Mem (a, b) (zipWith Prod.mk l₁ l₂)
⊢ a ∈ head✝¹ :: l₁ ∧ b ∈ head✝ :: l₂

Next tactic:
have := mem_zip h
theorem mem_zip {a b} : ∀ {l₁ : List α} {l₂ : List β}, (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂
  | _ :: l₁, _ :: l₂, h => by
    cases' h with _ _ _ h
    · simp
    · have := mem_zip h
      

Proof state:
case tail
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
b : β
head✝¹ : α
l₁ : List α
head✝ : β
l₂ : List β
h : Mem (a, b) (zipWith Prod.mk l₁ l₂)
this : a ∈ l₁ ∧ b ∈ l₂
⊢ a ∈ head✝¹ :: l₁ ∧ b ∈ head✝ :: l₂

Next tactic:
exact ⟨Mem.tail _ this.1, Mem.tail _ this.2⟩
theorem unzip_eq_map : ∀ l : List (α × β), unzip l = (l.map Prod.fst, l.map Prod.snd)
  | [] => rfl
  | (a, b) :: l => by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
b : β
l : List (α × β)
⊢ unzip ((a, b) :: l) = (map Prod.fst ((a, b) :: l), map Prod.snd ((a, b) :: l))

Next tactic:
simp only [unzip_cons, map_cons, unzip_eq_map l]
theorem unzip_left (l : List (α × β)) : (unzip l).1 = l.map Prod.fst := by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List (α × β)
⊢ (unzip l).1 = map Prod.fst l

Next tactic:
simp only [unzip_eq_map]
theorem unzip_right (l : List (α × β)) : (unzip l).2 = l.map Prod.snd := by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List (α × β)
⊢ (unzip l).2 = map Prod.snd l

Next tactic:
simp only [unzip_eq_map]
theorem unzip_swap (l : List (α × β)) : unzip (l.map Prod.swap) = (unzip l).swap := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List (α × β)
⊢ unzip (map Prod.swap l) = Prod.swap (unzip l)

Next tactic:
simp only [unzip_eq_map, map_map]
theorem unzip_swap (l : List (α × β)) : unzip (l.map Prod.swap) = (unzip l).swap := by
  simp only [unzip_eq_map, map_map]
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List (α × β)
⊢ (map (Prod.fst ∘ Prod.swap) l, map (Prod.snd ∘ Prod.swap) l) = Prod.swap (map Prod.fst l, map Prod.snd l)

Next tactic:
rfl
theorem zip_unzip : ∀ l : List (α × β), zip (unzip l).1 (unzip l).2 = l
  | [] => rfl
  | (a, b) :: l => by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
b : β
l : List (α × β)
⊢ zip (unzip ((a, b) :: l)).1 (unzip ((a, b) :: l)).2 = (a, b) :: l

Next tactic:
simp only [unzip_cons, zip_cons_cons, zip_unzip l]
theorem unzip_zip_left :
    ∀ {l₁ : List α} {l₂ : List β}, length l₁ ≤ length l₂ → (unzip (zip l₁ l₂)).1 = l₁
  | [], l₂, _ => rfl
  | l₁, [], h => by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
h : length l₁ ≤ length []
⊢ (unzip (zip l₁ [])).1 = l₁

Next tactic:
rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_le_zero h)]
theorem unzip_zip_left :
    ∀ {l₁ : List α} {l₂ : List β}, length l₁ ≤ length l₂ → (unzip (zip l₁ l₂)).1 = l₁
  | [], l₂, _ => rfl
  | l₁, [], h => by rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_le_zero h)]; 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
h : length l₁ ≤ length []
⊢ (unzip (zip [] [])).1 = []

Next tactic:
rfl
theorem unzip_zip_left :
    ∀ {l₁ : List α} {l₂ : List β}, length l₁ ≤ length l₂ → (unzip (zip l₁ l₂)).1 = l₁
  | [], l₂, _ => rfl
  | l₁, [], h => by rw [eq_nil_of_length_eq_zero (Nat.eq_zero_of_le_zero h)]; rfl
  | a :: l₁, b :: l₂, h => by
    

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
a : α
l₁ : List α
b : β
l₂ : List β
h : length (a :: l₁) ≤ length (b :: l₂)
⊢ (unzip (zip (a :: l₁) (b :: l₂))).1 = a :: l₁

Next tactic:
simp only [zip_cons_cons, unzip_cons, unzip_zip_left (le_of_succ_le_succ h)]
theorem unzip_zip_right {l₁ : List α} {l₂ : List β} (h : length l₂ ≤ length l₁) :
    (unzip (zip l₁ l₂)).2 = l₂ := by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
h : length l₂ ≤ length l₁
⊢ (unzip (zip l₁ l₂)).2 = l₂

Next tactic:
rw [← zip_swap, unzip_swap]
theorem unzip_zip_right {l₁ : List α} {l₂ : List β} (h : length l₂ ≤ length l₁) :
    (unzip (zip l₁ l₂)).2 = l₂ := by rw [← zip_swap, unzip_swap]; 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
h : length l₂ ≤ length l₁
⊢ (Prod.swap (unzip (zip l₂ l₁))).2 = l₂

Next tactic:
exact unzip_zip_left h
theorem unzip_zip {l₁ : List α} {l₂ : List β} (h : length l₁ = length l₂) :
    unzip (zip l₁ l₂) = (l₁, l₂) := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l₁ : List α
l₂ : List β
h : length l₁ = length l₂
⊢ unzip (zip l₁ l₂) = (l₁, l₂)

Next tactic:
rw [← Prod.mk.eta (p := unzip (zip l₁ l₂)),
    unzip_zip_left (le_of_eq h), unzip_zip_right (ge_of_eq h)]
theorem zip_of_prod {l : List α} {l' : List β} {lp : List (α × β)} (hl : lp.map Prod.fst = l)
    (hr : lp.map Prod.snd = l') : lp = l.zip l' := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
l' : List β
lp : List (α × β)
hl : map Prod.fst lp = l
hr : map Prod.snd lp = l'
⊢ lp = zip l l'

Next tactic:
rw [← hl, ← hr, ← zip_unzip lp, ← unzip_left, ← unzip_right, zip_unzip, zip_unzip]
theorem map_prod_left_eq_zip {l : List α} (f : α → β) :
    (l.map fun x => (x, f x)) = l.zip (l.map f) := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
f : α → β
⊢ map (fun x => (x, f x)) l = zip l (map f l)

Next tactic:
rw [← zip_map']
theorem map_prod_left_eq_zip {l : List α} (f : α → β) :
    (l.map fun x => (x, f x)) = l.zip (l.map f) := by
  rw [← zip_map']
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
f : α → β
⊢ zip (map (fun x => x) l) (map (fun x => f x) l) = zip l (map f l)

Next tactic:
congr
theorem map_prod_left_eq_zip {l : List α} (f : α → β) :
    (l.map fun x => (x, f x)) = l.zip (l.map f) := by
  rw [← zip_map']
  congr
  

Proof state:
case e_a
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
f : α → β
⊢ map (fun x => x) l = l

Next tactic:
exact map_id _
theorem map_prod_right_eq_zip {l : List α} (f : α → β) :
    (l.map fun x => (f x, x)) = (l.map f).zip l := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
f : α → β
⊢ map (fun x => (f x, x)) l = zip (map f l) l

Next tactic:
rw [← zip_map']
theorem map_prod_right_eq_zip {l : List α} (f : α → β) :
    (l.map fun x => (f x, x)) = (l.map f).zip l := by
  rw [← zip_map']
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
f : α → β
⊢ zip (map (fun x => f x) l) (map (fun x => x) l) = zip (map f l) l

Next tactic:
congr
theorem map_prod_right_eq_zip {l : List α} (f : α → β) :
    (l.map fun x => (f x, x)) = (l.map f).zip l := by
  rw [← zip_map']
  congr
  

Proof state:
case e_a
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
f : α → β
⊢ map (fun x => x) l = l

Next tactic:
exact map_id _
@[congr]
theorem zipWith_congr (f g : α → β → γ) (la : List α) (lb : List β)
    (h : List.Forall₂ (fun a b => f a b = g a b) la lb) : zipWith f la lb = zipWith g la lb := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f g : α → β → γ
la : List α
lb : List β
h : Forall₂ (fun a b => f a b = g a b) la lb
⊢ zipWith f la lb = zipWith g la lb

Next tactic:
induction' h with a b as bs hfg _ ih
@[congr]
theorem zipWith_congr (f g : α → β → γ) (la : List α) (lb : List β)
    (h : List.Forall₂ (fun a b => f a b = g a b) la lb) : zipWith f la lb = zipWith g la lb := by
  induction' h with a b as bs hfg _ ih
  · 

Proof state:
case nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f g : α → β → γ
la : List α
lb : List β
⊢ zipWith f [] [] = zipWith g [] []

Next tactic:
rfl
@[congr]
theorem zipWith_congr (f g : α → β → γ) (la : List α) (lb : List β)
    (h : List.Forall₂ (fun a b => f a b = g a b) la lb) : zipWith f la lb = zipWith g la lb := by
  induction' h with a b as bs hfg _ ih
  · rfl
  · 

Proof state:
case cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f g : α → β → γ
la : List α
lb : List β
a : α
b : β
as : List α
bs : List β
hfg : f a b = g a b
a✝ : Forall₂ (fun a b => f a b = g a b) as bs
ih : zipWith f as bs = zipWith g as bs
⊢ zipWith f (a :: as) (b :: bs) = zipWith g (a :: as) (b :: bs)

Next tactic:
exact congr_arg₂ _ hfg ih
theorem zipWith_comm_of_comm (f : α → α → β) (comm : ∀ x y : α, f x y = f y x) (l l' : List α) :
    zipWith f l l' = zipWith f l' l := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → α → β
comm : ∀ (x y : α), f x y = f y x
l l' : List α
⊢ zipWith f l l' = zipWith f l' l

Next tactic:
rw [zipWith_comm]
theorem zipWith_comm_of_comm (f : α → α → β) (comm : ∀ x y : α, f x y = f y x) (l l' : List α) :
    zipWith f l l' = zipWith f l' l := by
  rw [zipWith_comm]
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → α → β
comm : ∀ (x y : α), f x y = f y x
l l' : List α
⊢ zipWith (fun b a => f a b) l' l = zipWith f l' l

Next tactic:
simp only [comm]
@[simp]
theorem length_revzip (l : List α) : length (revzip l) = length l := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
⊢ length (revzip l) = length l

Next tactic:
simp only [revzip, length_zip, length_reverse, min_self]
@[simp]
theorem revzip_map_fst (l : List α) : (revzip l).map Prod.fst = l := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
⊢ map Prod.fst (revzip l) = l

Next tactic:
rw [← unzip_left, unzip_revzip]
@[simp]
theorem revzip_map_snd (l : List α) : (revzip l).map Prod.snd = l.reverse := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
⊢ map Prod.snd (revzip l) = reverse l

Next tactic:
rw [← unzip_right, unzip_revzip]
theorem reverse_revzip (l : List α) : reverse l.revzip = revzip l.reverse := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
⊢ reverse (revzip l) = revzip (reverse l)

Next tactic:
rw [← zip_unzip (revzip l).reverse]
theorem reverse_revzip (l : List α) : reverse l.revzip = revzip l.reverse := by
  rw [← zip_unzip (revzip l).reverse]
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
⊢ zip (unzip (reverse (revzip l))).1 (unzip (reverse (revzip l))).2 = revzip (reverse l)

Next tactic:
simp [unzip_eq_map, revzip, map_reverse, map_fst_zip, map_snd_zip]
theorem revzip_swap (l : List α) : (revzip l).map Prod.swap = revzip l.reverse := by 

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
l : List α
⊢ map Prod.swap (revzip l) = revzip (reverse l)

Next tactic:
simp [revzip]
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  

Proof state:
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l₁ : List α
l₂ : List β
i : ℕ
⊢ get? (zipWith f l₁ l₂) i = Option.bind (Option.map f (get? l₁ i)) fun g => Option.map g (get? l₂ i)

Next tactic:
induction' l₁ with head tail generalizing l₂ i
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · 

Proof state:
case nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l₂ : List β
i : ℕ
⊢ get? (zipWith f [] l₂) i = Option.bind (Option.map f (get? [] i)) fun g => Option.map g (get? l₂ i)

Next tactic:
rw [zipWith]
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> 

Proof state:
case nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l₂ : List β
i : ℕ
⊢ get? [] i = Option.bind (Option.map f (get? [] i)) fun g => Option.map g (get? l₂ i)

Next tactic:
simp
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> 

Proof state:
case nil.x_4
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
l₂ : List β
i : ℕ
⊢ ∀ (x : α) (xs : List α) (y : β) (ys : List β), [] = x :: xs → l₂ = y :: ys → False

Next tactic:
simp
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · 

Proof state:
case cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
l₂ : List β
i : ℕ
⊢ get? (zipWith f (head :: tail) l₂) i =
    Option.bind (Option.map f (get? (head :: tail) i)) fun g => Option.map g (get? l₂ i)

Next tactic:
cases l₂
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    

Proof state:
case cons.nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
i : ℕ
⊢ get? (zipWith f (head :: tail) []) i =
    Option.bind (Option.map f (get? (head :: tail) i)) fun g => Option.map g (get? [] i)
case cons.cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
i : ℕ
head✝ : β
tail✝ : List β
⊢ get? (zipWith f (head :: tail) (head✝ :: tail✝)) i =
    Option.bind (Option.map f (get? (head :: tail) i)) fun g => Option.map g (get? (head✝ :: tail✝) i)

Next tactic:
simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
    · 

Proof state:
case cons.nil
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
i : ℕ
⊢ none = Option.bind (Option.map f (get? (head :: tail) i)) fun g => none

Next tactic:
cases (head :: tail).get? i
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
    · cases (head :: tail).get? i <;> 

Proof state:
case cons.nil.none
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
i : ℕ
⊢ none = Option.bind (Option.map f none) fun g => none

Next tactic:
rfl
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
    · cases (head :: tail).get? i <;> 

Proof state:
case cons.nil.some
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
i : ℕ
val✝ : α
⊢ none = Option.bind (Option.map f (some val✝)) fun g => none

Next tactic:
rfl
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
    · cases (head :: tail).get? i <;> rfl
    · 

Proof state:
case cons.cons
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
i : ℕ
head✝ : β
tail✝ : List β
⊢ get? (zipWith f (head :: tail) (head✝ :: tail✝)) i =
    Option.bind (Option.map f (get? (head :: tail) i)) fun g => Option.map g (get? (head✝ :: tail✝) i)

Next tactic:
cases i
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
    · cases (head :: tail).get? i <;> rfl
    · cases i <;> 

Proof state:
case cons.cons.zero
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
head✝ : β
tail✝ : List β
⊢ get? (zipWith f (head :: tail) (head✝ :: tail✝)) zero =
    Option.bind (Option.map f (get? (head :: tail) zero)) fun g => Option.map g (get? (head✝ :: tail✝) zero)

Next tactic:
simp only [Option.map_some', get?, Option.some_bind', *]
theorem get?_zip_with (f : α → β → γ) (l₁ : List α) (l₂ : List β) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = ((l₁.get? i).map f).bind fun g => (l₂.get? i).map g := by
  induction' l₁ with head tail generalizing l₂ i
  · rw [zipWith] <;> simp
  · cases l₂
    simp only [zipWith, Seq.seq, Functor.map, get?, Option.map_none']
    · cases (head :: tail).get? i <;> rfl
    · cases i <;> 

Proof state:
case cons.cons.succ
α : Type u
β : Type u_1
γ : Type u_2
δ : Type u_3
ε : Type u_4
f : α → β → γ
head : α
tail : List α
tail_ih✝ :
  ∀ (l₂ : List β) (i : ℕ),
    get? (zipWith f tail l₂) i = Option.bind (Option.map f (get? tail i)) fun g => Option.map g (get? l₂ i)
head✝ : β
tail✝ : List β
n✝ : ℕ
⊢ get? (zipWith f (head :: tail) (head✝ :: tail✝)) (succ n✝) =
    Option.bind (Option.map f (get? (head :: tail) (succ n✝))) fun g => Option.map g (get? (head✝ :: tail✝) (succ n✝))

Next tactic:
simp only [Option.map_some', get?, Option.some_bind', *]
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  

Proof state:
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
l₁ : List α
l₂ : List β
z : γ
i : ℕ
⊢ get? (zipWith f l₁ l₂) i = some z ↔ ∃ x y, get? l₁ i = some x ∧ get? l₂ i = some y ∧ f x y = z

Next tactic:
induction l₁ generalizing l₂ i
theorem get?_zip_with_eq_some {α β γ} (f : α → β → γ) (l₁ : List α) (l₂ : List β) (z : γ) (i : ℕ) :
    (zipWith f l₁ l₂).get? i = some z ↔
      ∃ x y, l₁.get? i = some x ∧ l₂.get? i = some y ∧ f x y = z := by
  induction l₁ generalizing l₂ i
  · 

Proof state:
case nil
α✝ : Type u
β✝ : Type u_1
γ✝ : Type u_2
δ : Type u_3
ε : Type u_4
α : Type u_5
β : Type u_6
γ : Type u_7
f : α → β → γ
z : γ
l₂ : List β
i : ℕ
⊢ get? (zipWith f [] l₂) i = some z ↔ ∃ x y, get? [] i = some x ∧ get? l₂ i = some y ∧ f x y = z

Next tactic:
simp [zipWith]