l3lab/ntp-mathlib huggingface dataset:
theorem getLast?_append {l₁ l₂ : List α} {x : α} (h : x ∈ l₂.getLast?) :
    x ∈ (l₁ ++ l₂).getLast? := by
  cases l₂
  · contradiction
  · 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂ l₁ : List α
x head✝ : α
tail✝ : List α
h : x ∈ getLast? (head✝ :: tail✝)
⊢ x ∈ getLast? (l₁ ++ head✝ :: tail✝)

Next tactic:
rw [List.getLast?_append_cons]
theorem getLast?_append {l₁ l₂ : List α} {x : α} (h : x ∈ l₂.getLast?) :
    x ∈ (l₁ ++ l₂).getLast? := by
  cases l₂
  · contradiction
  · rw [List.getLast?_append_cons]
    

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂ l₁ : List α
x head✝ : α
tail✝ : List α
h : x ∈ getLast? (head✝ :: tail✝)
⊢ x ∈ getLast? (head✝ :: tail✝)

Next tactic:
exact h
theorem head!_eq_head? [Inhabited α] (l : List α) : head! l = (head? l).iget := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
l : List α
⊢ head! l = Option.iget (head? l)

Next tactic:
cases l
theorem head!_eq_head? [Inhabited α] (l : List α) : head! l = (head? l).iget := by cases l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
⊢ head! [] = Option.iget (head? [])

Next tactic:
rfl
theorem head!_eq_head? [Inhabited α] (l : List α) : head! l = (head? l).iget := by cases l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
head✝ : α
tail✝ : List α
⊢ head! (head✝ :: tail✝) = Option.iget (head? (head✝ :: tail✝))

Next tactic:
rfl
theorem eq_cons_of_mem_head? {x : α} : ∀ {l : List α}, x ∈ l.head? → l = x :: tail l
  | [], h => (Option.not_mem_none _ h).elim
  | a :: l, h => by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
x a : α
l : List α
h : x ∈ head? (a :: l)
⊢ a :: l = x :: tail (a :: l)

Next tactic:
simp only [head?, Option.mem_def, Option.some_inj] at h
theorem eq_cons_of_mem_head? {x : α} : ∀ {l : List α}, x ∈ l.head? → l = x :: tail l
  | [], h => (Option.not_mem_none _ h).elim
  | a :: l, h => by
    simp only [head?, Option.mem_def, Option.some_inj] at h
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
x a : α
l : List α
h : a = x
⊢ a :: l = x :: tail (a :: l)

Next tactic:
exact h ▸ rfl
@[simp]
theorem head!_append [Inhabited α] (t : List α) {s : List α} (h : s ≠ []) :
    head! (s ++ t) = head! s := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
t s : List α
h : s ≠ []
⊢ head! (s ++ t) = head! s

Next tactic:
induction s
@[simp]
theorem head!_append [Inhabited α] (t : List α) {s : List α} (h : s ≠ []) :
    head! (s ++ t) = head! s := by induction s; 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
t : List α
h : [] ≠ []
⊢ head! ([] ++ t) = head! []
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
t : List α
head✝ : α
tail✝ : List α
tail_ih✝ : tail✝ ≠ [] → head! (tail✝ ++ t) = head! tail✝
h : head✝ :: tail✝ ≠ []
⊢ head! (head✝ :: tail✝ ++ t) = head! (head✝ :: tail✝)

Next tactic:
contradiction
@[simp]
theorem head!_append [Inhabited α] (t : List α) {s : List α} (h : s ≠ []) :
    head! (s ++ t) = head! s := by induction s; contradiction; 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
t : List α
head✝ : α
tail✝ : List α
tail_ih✝ : tail✝ ≠ [] → head! (tail✝ ++ t) = head! tail✝
h : head✝ :: tail✝ ≠ []
⊢ head! (head✝ :: tail✝ ++ t) = head! (head✝ :: tail✝)

Next tactic:
rfl
theorem head?_append {s t : List α} {x : α} (h : x ∈ s.head?) : x ∈ (s ++ t).head? := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ s t : List α
x : α
h : x ∈ head? s
⊢ x ∈ head? (s ++ t)

Next tactic:
cases s
theorem head?_append {s t : List α} {x : α} (h : x ∈ s.head?) : x ∈ (s ++ t).head? := by
  cases s; 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ t : List α
x : α
h : x ∈ head? []
⊢ x ∈ head? ([] ++ t)
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ t : List α
x head✝ : α
tail✝ : List α
h : x ∈ head? (head✝ :: tail✝)
⊢ x ∈ head? (head✝ :: tail✝ ++ t)

Next tactic:
contradiction
theorem head?_append {s t : List α} {x : α} (h : x ∈ s.head?) : x ∈ (s ++ t).head? := by
  cases s; contradiction; 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ t : List α
x head✝ : α
tail✝ : List α
h : x ∈ head? (head✝ :: tail✝)
⊢ x ∈ head? (head✝ :: tail✝ ++ t)

Next tactic:
exact h
theorem tail_append_singleton_of_ne_nil {a : α} {l : List α} (h : l ≠ nil) :
    tail (l ++ [a]) = tail l ++ [a] := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
h : l ≠ []
⊢ tail (l ++ [a]) = tail l ++ [a]

Next tactic:
induction l
theorem tail_append_singleton_of_ne_nil {a : α} {l : List α} (h : l ≠ nil) :
    tail (l ++ [a]) = tail l ++ [a] := by
  induction l; 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
h : [] ≠ []
⊢ tail ([] ++ [a]) = tail [] ++ [a]
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
tail_ih✝ : tail✝ ≠ [] → tail (tail✝ ++ [a]) = tail tail✝ ++ [a]
h : head✝ :: tail✝ ≠ []
⊢ tail (head✝ :: tail✝ ++ [a]) = tail (head✝ :: tail✝) ++ [a]

Next tactic:
contradiction
theorem tail_append_singleton_of_ne_nil {a : α} {l : List α} (h : l ≠ nil) :
    tail (l ++ [a]) = tail l ++ [a] := by
  induction l; contradiction; 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
tail_ih✝ : tail✝ ≠ [] → tail (tail✝ ++ [a]) = tail tail✝ ++ [a]
h : head✝ :: tail✝ ≠ []
⊢ tail (head✝ :: tail✝ ++ [a]) = tail (head✝ :: tail✝) ++ [a]

Next tactic:
rw [tail, cons_append, tail]
theorem cons_head?_tail : ∀ {l : List α} {a : α}, a ∈ head? l → a :: tail l = l
  | [], a, h => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
h : a ∈ head? []
⊢ a :: tail [] = []

Next tactic:
contradiction
theorem cons_head?_tail : ∀ {l : List α} {a : α}, a ∈ head? l → a :: tail l = l
  | [], a, h => by contradiction
  | b :: l, a, h => by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
b : α
l : List α
a : α
h : a ∈ head? (b :: l)
⊢ a :: tail (b :: l) = b :: l

Next tactic:
simp? at h says simp only [head?_cons, Option.mem_def, Option.some.injEq] at h
theorem cons_head?_tail : ∀ {l : List α} {a : α}, a ∈ head? l → a :: tail l = l
  | [], a, h => by contradiction
  | b :: l, a, h => by
    simp? at h says 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
b : α
l : List α
a : α
h : a ∈ head? (b :: l)
⊢ a :: tail (b :: l) = b :: l

Next tactic:
simp only [head?_cons, Option.mem_def, Option.some.injEq] at h
theorem cons_head?_tail : ∀ {l : List α} {a : α}, a ∈ head? l → a :: tail l = l
  | [], a, h => by contradiction
  | b :: l, a, h => by
    simp? at h says simp only [head?_cons, Option.mem_def, Option.some.injEq] at h
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
b : α
l : List α
a : α
h : b = a
⊢ a :: tail (b :: l) = b :: l

Next tactic:
simp [h]
theorem head!_mem_head? [Inhabited α] : ∀ {l : List α}, l ≠ [] → head! l ∈ head? l
  | [], h => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
h : [] ≠ []
⊢ head! [] ∈ head? []

Next tactic:
contradiction
theorem head!_mem_self [Inhabited α] {l : List α} (h : l ≠ nil) : l.head! ∈ l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
l : List α
h : l ≠ []
⊢ head! l ∈ l

Next tactic:
have h' := mem_cons_self l.head! l.tail
theorem head!_mem_self [Inhabited α] {l : List α} (h : l ≠ nil) : l.head! ∈ l := by
  have h' := mem_cons_self l.head! l.tail
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
l : List α
h : l ≠ []
h' : head! l ∈ head! l :: tail l
⊢ head! l ∈ l

Next tactic:
rwa [cons_head!_tail h] at h'
theorem head_mem {l : List α} : ∀ (h : l ≠ nil), l.head h ∈ l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
⊢ ∀ (h : l ≠ []), head l h ∈ l

Next tactic:
cases l
theorem head_mem {l : List α} : ∀ (h : l ≠ nil), l.head h ∈ l := by
  cases l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
⊢ ∀ (h : [] ≠ []), head [] h ∈ []

Next tactic:
simp
theorem head_mem {l : List α} : ∀ (h : l ≠ nil), l.head h ∈ l := by
  cases l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
head✝ : α
tail✝ : List α
⊢ ∀ (h : head✝ :: tail✝ ≠ []), head (head✝ :: tail✝) h ∈ head✝ :: tail✝

Next tactic:
simp
@[simp]
theorem head?_map (f : α → β) (l) : head? (map f l) = (head? l).map f := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β
l : List α
⊢ head? (map f l) = Option.map f (head? l)

Next tactic:
cases l
@[simp]
theorem head?_map (f : α → β) (l) : head? (map f l) = (head? l).map f := by cases l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β
⊢ head? (map f []) = Option.map f (head? [])

Next tactic:
rfl
@[simp]
theorem head?_map (f : α → β) (l) : head? (map f l) = (head? l).map f := by cases l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β
head✝ : α
tail✝ : List α
⊢ head? (map f (head✝ :: tail✝)) = Option.map f (head? (head✝ :: tail✝))

Next tactic:
rfl
theorem tail_append_of_ne_nil (l l' : List α) (h : l ≠ []) : (l ++ l').tail = l.tail ++ l' := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l l' : List α
h : l ≠ []
⊢ tail (l ++ l') = tail l ++ l'

Next tactic:
cases l
theorem tail_append_of_ne_nil (l l' : List α) (h : l ≠ []) : (l ++ l').tail = l.tail ++ l' := by
  cases l
  · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l' : List α
h : [] ≠ []
⊢ tail ([] ++ l') = tail [] ++ l'

Next tactic:
contradiction
theorem tail_append_of_ne_nil (l l' : List α) (h : l ≠ []) : (l ++ l').tail = l.tail ++ l' := by
  cases l
  · contradiction
  · 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l' : List α
head✝ : α
tail✝ : List α
h : head✝ :: tail✝ ≠ []
⊢ tail (head✝ :: tail✝ ++ l') = tail (head✝ :: tail✝) ++ l'

Next tactic:
simp
@[simp] theorem nthLe_tail (l : List α) (i) (h : i < l.tail.length)
    (h' : i + 1 < l.length := (by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
i : ℕ
h : i < length (tail l)
⊢ i + 1 < length l

Next tactic:
simpa [← lt_tsub_iff_right] using h
@[simp] theorem nthLe_tail (l : List α) (i) (h : i < l.tail.length)
    (h' : i + 1 < l.length := (by simpa [← lt_tsub_iff_right] using h)) :
    l.tail.nthLe i h = l.nthLe (i + 1) h' := by
  -- Porting note: cases l <;> [cases h; rfl] fails
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
i : ℕ
h : i < length (tail l)
h' : optParam (i + 1 < length l) (_ : i + 1 < length l)
⊢ nthLe (tail l) i h = nthLe l (i + 1) h'

Next tactic:
cases l
@[simp] theorem nthLe_tail (l : List α) (i) (h : i < l.tail.length)
    (h' : i + 1 < l.length := (by simpa [← lt_tsub_iff_right] using h)) :
    l.tail.nthLe i h = l.nthLe (i + 1) h' := by
  -- Porting note: cases l <;> [cases h; rfl] fails
  cases l
  · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
i : ℕ
h : i < length (tail [])
h' : optParam (i + 1 < length []) (_ : i + 1 < length [])
⊢ nthLe (tail []) i h = nthLe [] (i + 1) h'

Next tactic:
cases h
@[simp] theorem nthLe_tail (l : List α) (i) (h : i < l.tail.length)
    (h' : i + 1 < l.length := (by simpa [← lt_tsub_iff_right] using h)) :
    l.tail.nthLe i h = l.nthLe (i + 1) h' := by
  -- Porting note: cases l <;> [cases h; rfl] fails
  cases l
  · cases h
  · 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
i : ℕ
head✝ : α
tail✝ : List α
h : i < length (tail (head✝ :: tail✝))
h' : optParam (i + 1 < length (head✝ :: tail✝)) (_ : i + 1 < length (head✝ :: tail✝))
⊢ nthLe (tail (head✝ :: tail✝)) i h = nthLe (head✝ :: tail✝) (i + 1) h'

Next tactic:
rfl
theorem nthLe_cons_aux {l : List α} {a : α} {n} (hn : n ≠ 0) (h : n < (a :: l).length) :
    n - 1 < l.length := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hn : n ≠ 0
h : n < length (a :: l)
⊢ n - 1 < length l

Next tactic:
contrapose! h
theorem nthLe_cons_aux {l : List α} {a : α} {n} (hn : n ≠ 0) (h : n < (a :: l).length) :
    n - 1 < l.length := by
  contrapose! h
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hn : n ≠ 0
h : length l ≤ n - 1
⊢ length (a :: l) ≤ n

Next tactic:
rw [length_cons]
theorem nthLe_cons_aux {l : List α} {a : α} {n} (hn : n ≠ 0) (h : n < (a :: l).length) :
    n - 1 < l.length := by
  contrapose! h
  rw [length_cons]
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hn : n ≠ 0
h : length l ≤ n - 1
⊢ succ (length l) ≤ n

Next tactic:
convert succ_le_succ h
theorem nthLe_cons_aux {l : List α} {a : α} {n} (hn : n ≠ 0) (h : n < (a :: l).length) :
    n - 1 < l.length := by
  contrapose! h
  rw [length_cons]
  convert succ_le_succ h
  

Proof state:
case h.e'_4
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hn : n ≠ 0
h : length l ≤ n - 1
⊢ n = succ (n - 1)

Next tactic:
exact (Nat.succ_pred_eq_of_pos hn.bot_lt).symm
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hl : n < length (a :: l)
⊢ nthLe (a :: l) n hl = if hn : n = 0 then a else nthLe l (n - 1) (_ : n - 1 < length l)

Next tactic:
split_ifs with h
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hl : n < length (a :: l)
h : n = 0
⊢ nthLe (a :: l) n hl = a

Next tactic:
simp [nthLe, h]
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · simp [nthLe, h]
  

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
hl : n < length (a :: l)
h : ¬n = 0
⊢ nthLe (a :: l) n hl = nthLe l (n - 1) (_ : n - 1 < length l)

Next tactic:
cases l
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · simp [nthLe, h]
  cases l
  · 

Proof state:
case neg.nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n : ℕ
h : ¬n = 0
hl : n < length [a]
⊢ nthLe [a] n hl = nthLe [] (n - 1) (_ : n - 1 < length [])

Next tactic:
rw [length_singleton, lt_succ_iff, nonpos_iff_eq_zero] at hl
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · simp [nthLe, h]
  cases l
  · rw [length_singleton, lt_succ_iff, nonpos_iff_eq_zero] at hl
    

Proof state:
case neg.nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n : ℕ
h : ¬n = 0
hl✝ : n < length [a]
hl : n = 0
⊢ nthLe [a] n hl✝ = nthLe [] (n - 1) (_ : n - 1 < length [])

Next tactic:
contradiction
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · simp [nthLe, h]
  cases l
  · rw [length_singleton, lt_succ_iff, nonpos_iff_eq_zero] at hl
    contradiction
  

Proof state:
case neg.cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n : ℕ
h : ¬n = 0
head✝ : α
tail✝ : List α
hl : n < length (a :: head✝ :: tail✝)
⊢ nthLe (a :: head✝ :: tail✝) n hl = nthLe (head✝ :: tail✝) (n - 1) (_ : n - 1 < length (head✝ :: tail✝))

Next tactic:
cases n
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · simp [nthLe, h]
  cases l
  · rw [length_singleton, lt_succ_iff, nonpos_iff_eq_zero] at hl
    contradiction
  cases n
  · 

Proof state:
case neg.cons.zero
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
h : ¬zero = 0
hl : zero < length (a :: head✝ :: tail✝)
⊢ nthLe (a :: head✝ :: tail✝) zero hl = nthLe (head✝ :: tail✝) (zero - 1) (_ : zero - 1 < length (head✝ :: tail✝))

Next tactic:
contradiction
theorem nthLe_cons {l : List α} {a : α} {n} (hl) :
    (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by
  split_ifs with h
  · simp [nthLe, h]
  cases l
  · rw [length_singleton, lt_succ_iff, nonpos_iff_eq_zero] at hl
    contradiction
  cases n
  · contradiction
  

Proof state:
case neg.cons.succ
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
n✝ : ℕ
h : ¬succ n✝ = 0
hl : succ n✝ < length (a :: head✝ :: tail✝)
⊢ nthLe (a :: head✝ :: tail✝) (succ n✝) hl =
    nthLe (head✝ :: tail✝) (succ n✝ - 1) (_ : succ n✝ - 1 < length (head✝ :: tail✝))

Next tactic:
rfl
@[simp 1100, nolint simpNF]
theorem modifyHead_modifyHead (l : List α) (f g : α → α) :
    (l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
f g : α → α
⊢ modifyHead g (modifyHead f l) = modifyHead (g ∘ f) l

Next tactic:
cases l
@[simp 1100, nolint simpNF]
theorem modifyHead_modifyHead (l : List α) (f g : α → α) :
    (l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by cases l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → α
⊢ modifyHead g (modifyHead f []) = modifyHead (g ∘ f) []

Next tactic:
simp
@[simp 1100, nolint simpNF]
theorem modifyHead_modifyHead (l : List α) (f g : α → α) :
    (l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by cases l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f g : α → α
head✝ : α
tail✝ : List α
⊢ modifyHead g (modifyHead f (head✝ :: tail✝)) = modifyHead (g ∘ f) (head✝ :: tail✝)

Next tactic:
simp
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
⊢ C l

Next tactic:
rw [← reverse_reverse l]
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
⊢ C (reverse (reverse l))

Next tactic:
match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    have : tail.length < l.length := by
      rw [← length_reverse l, h, length_cons]
      simp [Nat.lt_succ]
    let ih := reverseRecOn (reverse tail) H0 H1
    rw [reverse_cons]
    exact H1 _ _ ih
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
h : reverse l = []
⊢ C (reverse [])

Next tactic:
exact H0
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
head : α
tail : List α
h : reverse l = head :: tail
⊢ C (reverse (head :: tail))

Next tactic:
have : tail.length < l.length := by
      rw [← length_reverse l, h, length_cons]
      simp [Nat.lt_succ]
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    have : tail.length < l.length := by
      

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
head : α
tail : List α
h : reverse l = head :: tail
⊢ length tail < length l

Next tactic:
rw [← length_reverse l, h, length_cons]
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    have : tail.length < l.length := by
      rw [← length_reverse l, h, length_cons]
      

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
head : α
tail : List α
h : reverse l = head :: tail
⊢ length tail < succ (length tail)

Next tactic:
simp [Nat.lt_succ]