Theorem: Array.zipWith_eq_zipWith_data
File: .lake/packages/batteries/Batteries/Data/Array/Lemmas.lean

tactic: simp [zipWith, loop 0 #[] (by simp) (by simp)]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
⊢ (as.zipWith bs f).data = List.zipWith f as.data bs.data
state_after: no goals

tactic: intro i cs hia hib
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
⊢ ∀ (i : Nat) (cs : Array γ),
    i ≤ as.size →
      i ≤ bs.size →
        (zipWithAux f as bs i cs).data = cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
⊢ (zipWithAux f as bs i cs).data = cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: unfold zipWithAux
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
⊢ (zipWithAux f as bs i cs).data = cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: by_cases h : i = as.size ∨ i = bs.size
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case pos
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

case neg
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬(i = as.size ∨ i = bs.size)
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: case neg =>
  rw [not_or] at h
  have has : i < as.size := Nat.lt_of_le_of_ne hia h.1
  have hbs : i < bs.size := Nat.lt_of_le_of_ne hib h.2
  simp only [has, hbs, dite_true]
  rw [loop (i+1) _ has hbs, Array.push_data]
  have h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]] := rfl
  let i_as : Fin as.data.length := ⟨i, has⟩
  let i_bs : Fin bs.data.length := ⟨i, hbs⟩
  rw [h₁, List.append_assoc]
  congr
  rw [← List.zipWith_append (h := by simp), getElem_eq_data_getElem, getElem_eq_data_getElem]
  show List.zipWith f (as.data[i_as] :: List.drop (i_as + 1) as.data)
    ((List.get bs.data i_bs) :: List.drop (i_bs + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)
  simp only [data_length, Fin.getElem_fin, List.getElem_cons_drop, List.get_eq_getElem]
state_before: case neg
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬(i = as.size ∨ i = bs.size)
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: no goals

tactic: have : ¬(i < as.size) ∨ ¬(i < bs.size) := by
  cases h <;> simp_all only [Nat.not_lt, Nat.le_refl, true_or, or_true]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
this : ¬i < as.size ∨ ¬i < bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: simp_all only [Nat.not_lt]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
this : ¬i < as.size ∨ ¬i < bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
this : as.size ≤ i ∨ bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: cases h <;> [(cases this); (cases this)]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
this : as.size ≤ i ∨ bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case inl.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = as.size
h✝ : as.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

case inl.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = as.size
h✝ : bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

case inr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = bs.size
h✝ : as.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

case inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = bs.size
h✝ : bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: cases h <;> simp_all only [Nat.not_lt, Nat.le_refl, true_or, or_true]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : i = as.size ∨ i = bs.size
⊢ ¬i < as.size ∨ ¬i < bs.size
state_after: no goals

tactic: cases this
state_before: case inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
this : as.size ≤ i ∨ bs.size ≤ i
h✝ : i = as.size
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case inl.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = as.size
h✝ : as.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

case inl.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = as.size
h✝ : bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: cases this
state_before: case inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
this : as.size ≤ i ∨ bs.size ≤ i
h✝ : i = bs.size
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case inr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = bs.size
h✝ : as.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

case inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = bs.size
h✝ : bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: simp_all only [Nat.le_refl, Nat.lt_irrefl, dite_false, List.drop_length,
              List.zipWith_nil_left, List.append_nil]
state_before: case inl.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = as.size
h✝ : as.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: no goals

tactic: simp_all only [Nat.le_refl, Nat.lt_irrefl, dite_false, List.drop_length,
              List.zipWith_nil_left, List.append_nil]
state_before: case inl.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = as.size
h✝ : bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: no goals

tactic: simp_all only [Nat.le_refl, Nat.lt_irrefl, dite_false, List.drop_length,
              List.zipWith_nil_right, List.append_nil]
state_before: case inr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = bs.size
h✝ : as.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case inr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : bs.size ≤ as.size
h✝¹ : i = bs.size
h✝ : as.size ≤ bs.size
⊢ (if h : bs.size < as.size then cs else cs).data = cs.data

tactic: split <;> simp_all only [Nat.not_lt]
state_before: case inr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : bs.size ≤ as.size
h✝¹ : i = bs.size
h✝ : as.size ≤ bs.size
⊢ (if h : bs.size < as.size then cs else cs).data = cs.data
state_after: no goals

tactic: simp_all only [Nat.le_refl, Nat.lt_irrefl, dite_false, List.drop_length,
              List.zipWith_nil_right, List.append_nil]
state_before: case inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h✝¹ : i = bs.size
h✝ : bs.size ≤ i
⊢ (if h : i < as.size then if h_1 : i < bs.size then zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i])) else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : bs.size ≤ as.size
h✝ : i = bs.size
⊢ (if h : bs.size < as.size then cs else cs).data = cs.data

tactic: split <;> simp_all only [Nat.not_lt]
state_before: case inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : bs.size ≤ as.size
h✝ : i = bs.size
⊢ (if h : bs.size < as.size then cs else cs).data = cs.data
state_after: no goals

tactic: rw [not_or] at h
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬(i = as.size ∨ i = bs.size)
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: have has : i < as.size := Nat.lt_of_le_of_ne hia h.1
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: have hbs : i < bs.size := Nat.lt_of_le_of_ne hib h.2
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: simp only [has, hbs, dite_true]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
⊢ (if h : i < as.size then
        let a := as[i];
        if h : i < bs.size then
          let b := bs[i];
          zipWithAux f as bs (i + 1) (cs.push (f a b))
        else cs
      else cs).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
⊢ (zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i]))).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: rw [loop (i+1) _ has hbs, Array.push_data]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
⊢ (zipWithAux f as bs (i + 1) (cs.push (f as[i] bs[i]))).data =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: have h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]] := rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: let i_as : Fin as.data.length := ⟨i, has⟩
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: let i_bs : Fin bs.data.length := ⟨i, hbs⟩
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: rw [h₁, List.append_assoc]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ cs.data ++ [f as[i] bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ cs.data ++
      (List.zipWith f [as[i]] [bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data)) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: congr
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ cs.data ++
      (List.zipWith f [as[i]] [bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data)) =
    cs.data ++ List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ List.zipWith f [as[i]] [bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: rw [← List.zipWith_append (h := by simp), getElem_eq_data_getElem, getElem_eq_data_getElem]
state_before: case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ List.zipWith f [as[i]] [bs[i]] ++ List.zipWith f (List.drop (i + 1) as.data) (List.drop (i + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ List.zipWith f ([as.data[i]] ++ List.drop (i + 1) as.data) ([bs.data[i]] ++ List.drop (i + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: show List.zipWith f (as.data[i_as] :: List.drop (i_as + 1) as.data)
  ((List.get bs.data i_bs) :: List.drop (i_bs + 1) bs.data) =
  List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_before: case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ List.zipWith f ([as.data[i]] ++ List.drop (i + 1) as.data) ([bs.data[i]] ++ List.drop (i + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ List.zipWith f (as.data[i_as] :: List.drop (↑i_as + 1) as.data) (bs.data.get i_bs :: List.drop (↑i_bs + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)

tactic: simp only [data_length, Fin.getElem_fin, List.getElem_cons_drop, List.get_eq_getElem]
state_before: case e_a
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f as[i] bs[i]] = List.zipWith f [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
⊢ List.zipWith f (as.data[i_as] :: List.drop (↑i_as + 1) as.data) (bs.data.get i_bs :: List.drop (↑i_bs + 1) bs.data) =
    List.zipWith f (List.drop i as.data) (List.drop i bs.data)
state_after: no goals

tactic: simp
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f✝ : α → β → γ
as : Array α
bs : Array β
i : Nat
cs : Array γ
hia : i ≤ as.size
hib : i ≤ bs.size
h : ¬i = as.size ∧ ¬i = bs.size
has : i < as.size
hbs : i < bs.size
h₁ : [f✝ as[i] bs[i]] = List.zipWith f✝ [as[i]] [bs[i]]
i_as : Fin as.data.length := ⟨i, has⟩
i_bs : Fin bs.data.length := ⟨i, hbs⟩
f : α → β → γ
la : List α
lb : List β
⊢ [as[i]].length = [bs[i]].length
state_after: no goals

tactic: simp
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
⊢ 0 ≤ as.size
state_after: no goals

tactic: simp
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → γ
as : Array α
bs : Array β
⊢ 0 ≤ bs.size
state_after: no goals