l3lab/ntp-mathlib huggingface dataset:
theorem nodup_iff_injective_get {v : Vector α n} : v.toList.Nodup ↔ Function.Injective v.get := by
  cases' v with l hl
  

Proof state:
case mk
n : ℕ
α : Type u_1
l : List α
hl : List.length l = n
⊢ List.Nodup (toList { val := l, property := hl }) ↔ Function.Injective (get { val := l, property := hl })

Next tactic:
subst hl
theorem nodup_iff_injective_get {v : Vector α n} : v.toList.Nodup ↔ Function.Injective v.get := by
  cases' v with l hl
  subst hl
  

Proof state:
case mk
α : Type u_1
l : List α
⊢ List.Nodup (toList { val := l, property := (_ : List.length l = List.length l) }) ↔
    Function.Injective (get { val := l, property := (_ : List.length l = List.length l) })

Next tactic:
exact List.nodup_iff_injective_get
/-- Reverse a vector. -/
def reverse (v : Vector α n) : Vector α n :=
  ⟨v.toList.reverse, by 

Proof state:
n : ℕ
α : Type u_1
v : Vector α n
⊢ List.length (List.reverse (toList v)) = n

Next tactic:
simp
@[simp]
theorem reverse_reverse {v : Vector α n} : v.reverse.reverse = v := by
  

Proof state:
n : ℕ
α : Type u_1
v : Vector α n
⊢ reverse (reverse v) = v

Next tactic:
cases v
@[simp]
theorem reverse_reverse {v : Vector α n} : v.reverse.reverse = v := by
  cases v
  

Proof state:
case mk
n : ℕ
α : Type u_1
val✝ : List α
property✝ : List.length val✝ = n
⊢ reverse (reverse { val := val✝, property := property✝ }) = { val := val✝, property := property✝ }

Next tactic:
simp [Vector.reverse]
@[simp]
theorem head_ofFn {n : ℕ} (f : Fin n.succ → α) : head (ofFn f) = f 0 := by
  

Proof state:
n✝ : ℕ
α : Type u_1
n : ℕ
f : Fin (Nat.succ n) → α
⊢ head (ofFn f) = f 0

Next tactic:
rw [← get_zero, get_ofFn]
theorem get_cons_zero (a : α) (v : Vector α n) : get (a ::ᵥ v) 0 = a := by 

Proof state:
n : ℕ
α : Type u_1
a : α
v : Vector α n
⊢ get (a ::ᵥ v) 0 = a

Next tactic:
simp [get_zero]
@[simp]
theorem get_cons_succ (a : α) (v : Vector α n) (i : Fin n) : get (a ::ᵥ v) i.succ = get v i := by
  

Proof state:
n : ℕ
α : Type u_1
a : α
v : Vector α n
i : Fin n
⊢ get (a ::ᵥ v) (Fin.succ i) = get v i

Next tactic:
rw [← get_tail_succ, tail_cons]
/-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  

Proof state:
n : ℕ
α : Type u_1
v : Vector α (n + 1)
⊢ head (reverse v) = last v

Next tactic:
rw [← get_zero, last_def, get_eq_get, get_eq_get]
/-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  rw [← get_zero, last_def, get_eq_get, get_eq_get]
  

Proof state:
n : ℕ
α : Type u_1
v : Vector α (n + 1)
⊢ List.get (toList (reverse v)) (Fin.cast (_ : Nat.succ n = List.length (toList (reverse v))) 0) =
    List.get (toList v) (Fin.cast (_ : n + 1 = List.length (toList v)) (Fin.last n))

Next tactic:
simp_rw [toList_reverse]
/-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  rw [← get_zero, last_def, get_eq_get, get_eq_get]
  simp_rw [toList_reverse]
  

Proof state:
n : ℕ
α : Type u_1
v : Vector α (n + 1)
⊢ List.get (List.reverse (toList v)) (Fin.cast (_ : Nat.succ n = List.length (toList (reverse v))) 0) =
    List.get (toList v) (Fin.cast (_ : n + 1 = List.length (toList v)) (Fin.last n))

Next tactic:
rw [← Option.some_inj, Fin.cast, Fin.cast, ← List.get?_eq_get, ← List.get?_eq_get,
    List.get?_reverse]
/-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  rw [← get_zero, last_def, get_eq_get, get_eq_get]
  simp_rw [toList_reverse]
  rw [← Option.some_inj, Fin.cast, Fin.cast, ← List.get?_eq_get, ← List.get?_eq_get,
    List.get?_reverse]
  · 

Proof state:
n : ℕ
α : Type u_1
v : Vector α (n + 1)
⊢ List.get? (toList v) (List.length (toList v) - 1 - ↑0) = List.get? (toList v) ↑(Fin.last n)

Next tactic:
congr
/-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  rw [← get_zero, last_def, get_eq_get, get_eq_get]
  simp_rw [toList_reverse]
  rw [← Option.some_inj, Fin.cast, Fin.cast, ← List.get?_eq_get, ← List.get?_eq_get,
    List.get?_reverse]
  · congr
    

Proof state:
case e_a
n : ℕ
α : Type u_1
v : Vector α (n + 1)
⊢ List.length (toList v) - 1 - ↑0 = ↑(Fin.last n)

Next tactic:
simp
/-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  rw [← get_zero, last_def, get_eq_get, get_eq_get]
  simp_rw [toList_reverse]
  rw [← Option.some_inj, Fin.cast, Fin.cast, ← List.get?_eq_get, ← List.get?_eq_get,
    List.get?_reverse]
  · congr
    simp
  · 

Proof state:
case h
n : ℕ
α : Type u_1
v : Vector α (n + 1)
⊢ ↑0 < List.length (toList v)

Next tactic:
simp
/-- Construct a `Vector β (n + 1)` from a `Vector α n` by scanning `f : β → α → β`
from the "left", that is, from 0 to `Fin.last n`, using `b : β` as the starting value.
-/
def scanl : Vector β (n + 1) :=
  ⟨List.scanl f b v.toList, by 

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
⊢ List.length (List.scanl f b (toList v)) = n + 1

Next tactic:
rw [List.length_scanl, toList_length]
/-- The recursive step of `scanl` splits a vector `x ::ᵥ v : Vector α (n + 1)`
into the provided starting value `b : β` and the recursed `scanl`
`f b x : β` as the starting value.

This lemma is the `cons` version of `scanl_get`.
-/
@[simp]
theorem scanl_cons (x : α) : scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v := by
  

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
x : α
⊢ scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v

Next tactic:
simp only [scanl, toList_cons, List.scanl]
/-- The recursive step of `scanl` splits a vector `x ::ᵥ v : Vector α (n + 1)`
into the provided starting value `b : β` and the recursed `scanl`
`f b x : β` as the starting value.

This lemma is the `cons` version of `scanl_get`.
-/
@[simp]
theorem scanl_cons (x : α) : scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v := by
  simp only [scanl, toList_cons, List.scanl]; 

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
x : α
⊢ { val := b :: List.scanl f (f b x) ↑v,
      property := (_ : (fun l => List.length l = Nat.succ n + 1) (b :: List.scanl f (f b x) ↑v)) } =
    b ::ᵥ
      { val := List.scanl f (f b x) (toList v),
        property := (_ : List.length (List.scanl f (f b x) (toList v)) = n + 1) }

Next tactic:
dsimp
/-- The recursive step of `scanl` splits a vector `x ::ᵥ v : Vector α (n + 1)`
into the provided starting value `b : β` and the recursed `scanl`
`f b x : β` as the starting value.

This lemma is the `cons` version of `scanl_get`.
-/
@[simp]
theorem scanl_cons (x : α) : scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v := by
  simp only [scanl, toList_cons, List.scanl]; dsimp
  

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
x : α
⊢ { val := b :: List.scanl f (f b x) ↑v,
      property := (_ : List.length (List.scanl f b (toList (x ::ᵥ v))) = Nat.succ n + 1) } =
    b ::ᵥ
      { val := List.scanl f (f b x) (toList v),
        property := (_ : List.length (List.scanl f (f b x) (toList v)) = n + 1) }

Next tactic:
simp only [cons]
/-- The recursive step of `scanl` splits a vector `x ::ᵥ v : Vector α (n + 1)`
into the provided starting value `b : β` and the recursed `scanl`
`f b x : β` as the starting value.

This lemma is the `cons` version of `scanl_get`.
-/
@[simp]
theorem scanl_cons (x : α) : scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v := by
  simp only [scanl, toList_cons, List.scanl]; dsimp
  simp only [cons]; 

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
x : α
⊢ { val := b :: List.scanl f (f b x) ↑v,
      property := (_ : List.length (List.scanl f b (toList (x ::ᵥ v))) = Nat.succ n + 1) } =
    { val := b :: List.scanl f (f b x) (toList v),
      property := (_ : Nat.succ (List.length (List.scanl f (f b x) (toList v))) = Nat.succ (n + 1)) }

Next tactic:
rfl
/-- The recursive step of `scanl` splits a vector made up of a single element
`x ::ᵥ nil : Vector α 1` into a `Vector` of the provided starting value `b : β`
and the mapped `f b x : β` as the last value.
-/
@[simp]
theorem scanl_singleton (v : Vector α 1) : scanl f b v = b ::ᵥ f b v.head ::ᵥ nil := by
  

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v✝ : Vector α n
v : Vector α 1
⊢ scanl f b v = b ::ᵥ f b (head v) ::ᵥ nil

Next tactic:
rw [← cons_head_tail v]
/-- The recursive step of `scanl` splits a vector made up of a single element
`x ::ᵥ nil : Vector α 1` into a `Vector` of the provided starting value `b : β`
and the mapped `f b x : β` as the last value.
-/
@[simp]
theorem scanl_singleton (v : Vector α 1) : scanl f b v = b ::ᵥ f b v.head ::ᵥ nil := by
  rw [← cons_head_tail v]
  

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v✝ : Vector α n
v : Vector α 1
⊢ scanl f b (head v ::ᵥ tail v) = b ::ᵥ f b (head (head v ::ᵥ tail v)) ::ᵥ nil

Next tactic:
simp only [scanl_cons, scanl_nil, head_cons, singleton_tail]
/-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
⊢ head (scanl f b v) = b

Next tactic:
cases n
/-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  cases n
  · 

Proof state:
case zero
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α Nat.zero
⊢ head (scanl f b v) = b

Next tactic:
have : v = nil := by simp only [Nat.zero_eq, eq_iff_true_of_subsingleton]
/-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  cases n
  · have : v = nil := by 

Proof state:
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α Nat.zero
⊢ v = nil

Next tactic:
simp only [Nat.zero_eq, eq_iff_true_of_subsingleton]
/-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  cases n
  · have : v = nil := by simp only [Nat.zero_eq, eq_iff_true_of_subsingleton]
    

Proof state:
case zero
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α Nat.zero
this : v = nil
⊢ head (scanl f b v) = b

Next tactic:
simp only [this, scanl_nil, head_cons]
/-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  cases n
  · have : v = nil := by simp only [Nat.zero_eq, eq_iff_true_of_subsingleton]
    simp only [this, scanl_nil, head_cons]
  · 

Proof state:
case succ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
n✝ : ℕ
v : Vector α (Nat.succ n✝)
⊢ head (scanl f b v) = b

Next tactic:
rw [← cons_head_tail v]
/-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  cases n
  · have : v = nil := by simp only [Nat.zero_eq, eq_iff_true_of_subsingleton]
    simp only [this, scanl_nil, head_cons]
  · rw [← cons_head_tail v]
    

Proof state:
case succ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
n✝ : ℕ
v : Vector α (Nat.succ n✝)
⊢ head (scanl f b (head v ::ᵥ tail v)) = b

Next tactic:
simp only [← get_zero, get_eq_get, toList_scanl, toList_cons, List.scanl, Fin.val_zero,
      List.get]
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  

Proof state:
n : ℕ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α n
i : Fin n
⊢ get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)

Next tactic:
cases' n with n
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · 

Proof state:
case zero
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α Nat.zero
i : Fin Nat.zero
⊢ get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)

Next tactic:
exact i.elim0
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  

Proof state:
case succ
α : Type u_1
β : Type u_2
f : β → α → β
b : β
n : ℕ
v : Vector α (Nat.succ n)
i : Fin (Nat.succ n)
⊢ get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)

Next tactic:
induction' n with n hn generalizing b
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · 

Proof state:
case succ.zero
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α (Nat.succ Nat.zero)
i : Fin (Nat.succ Nat.zero)
⊢ get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)

Next tactic:
have i0 : i = 0 := Fin.eq_zero _
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    

Proof state:
case succ.zero
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α (Nat.succ Nat.zero)
i : Fin (Nat.succ Nat.zero)
i0 : i = 0
⊢ get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)

Next tactic:
simp [scanl_singleton, i0, get_zero]
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; 

Proof state:
case succ.zero
α : Type u_1
β : Type u_2
f : β → α → β
b : β
v : Vector α (Nat.succ Nat.zero)
i : Fin (Nat.succ Nat.zero)
i0 : i = 0
⊢ get (b ::ᵥ f b (head v) ::ᵥ nil) 1 = f b (head v)

Next tactic:
simp [get_eq_get, List.get]
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; simp [get_eq_get, List.get]
  · 

Proof state:
case succ.succ
α : Type u_1
β : Type u_2
f : β → α → β
n : ℕ
hn :
  ∀ (b : β) (v : Vector α (Nat.succ n)) (i : Fin (Nat.succ n)),
    get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)
b : β
v : Vector α (Nat.succ (Nat.succ n))
i : Fin (Nat.succ (Nat.succ n))
⊢ get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)

Next tactic:
rw [← cons_head_tail v, scanl_cons, get_cons_succ]
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; simp [get_eq_get, List.get]
  · rw [← cons_head_tail v, scanl_cons, get_cons_succ]
    

Proof state:
case succ.succ
α : Type u_1
β : Type u_2
f : β → α → β
n : ℕ
hn :
  ∀ (b : β) (v : Vector α (Nat.succ n)) (i : Fin (Nat.succ n)),
    get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)
b : β
v : Vector α (Nat.succ (Nat.succ n))
i : Fin (Nat.succ (Nat.succ n))
⊢ get (scanl f (f b (head v)) (tail v)) i =
    f (get (b ::ᵥ scanl f (f b (head v)) (tail v)) (Fin.castSucc i)) (get (head v ::ᵥ tail v) i)

Next tactic:
refine' Fin.cases _ _ i
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; simp [get_eq_get, List.get]
  · rw [← cons_head_tail v, scanl_cons, get_cons_succ]
    refine' Fin.cases _ _ i
    · 

Proof state:
case succ.succ.refine'_1
α : Type u_1
β : Type u_2
f : β → α → β
n : ℕ
hn :
  ∀ (b : β) (v : Vector α (Nat.succ n)) (i : Fin (Nat.succ n)),
    get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)
b : β
v : Vector α (Nat.succ (Nat.succ n))
i : Fin (Nat.succ (Nat.succ n))
⊢ get (scanl f (f b (head v)) (tail v)) 0 =
    f (get (b ::ᵥ scanl f (f b (head v)) (tail v)) (Fin.castSucc 0)) (get (head v ::ᵥ tail v) 0)

Next tactic:
simp only [get_zero, scanl_head, Fin.castSucc_zero, head_cons]
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; simp [get_eq_get, List.get]
  · rw [← cons_head_tail v, scanl_cons, get_cons_succ]
    refine' Fin.cases _ _ i
    · simp only [get_zero, scanl_head, Fin.castSucc_zero, head_cons]
    · 

Proof state:
case succ.succ.refine'_2
α : Type u_1
β : Type u_2
f : β → α → β
n : ℕ
hn :
  ∀ (b : β) (v : Vector α (Nat.succ n)) (i : Fin (Nat.succ n)),
    get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)
b : β
v : Vector α (Nat.succ (Nat.succ n))
i : Fin (Nat.succ (Nat.succ n))
⊢ ∀ (i : Fin (n + 1)),
    get (scanl f (f b (head v)) (tail v)) (Fin.succ i) =
      f (get (b ::ᵥ scanl f (f b (head v)) (tail v)) (Fin.castSucc (Fin.succ i))) (get (head v ::ᵥ tail v) (Fin.succ i))

Next tactic:
intro i'
/-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.

This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  cases' n with n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; simp [get_eq_get, List.get]
  · rw [← cons_head_tail v, scanl_cons, get_cons_succ]
    refine' Fin.cases _ _ i
    · simp only [get_zero, scanl_head, Fin.castSucc_zero, head_cons]
    · intro i'
      

Proof state:
case succ.succ.refine'_2
α : Type u_1
β : Type u_2
f : β → α → β
n : ℕ
hn :
  ∀ (b : β) (v : Vector α (Nat.succ n)) (i : Fin (Nat.succ n)),
    get (scanl f b v) (Fin.succ i) = f (get (scanl f b v) (Fin.castSucc i)) (get v i)
b : β
v : Vector α (Nat.succ (Nat.succ n))
i : Fin (Nat.succ (Nat.succ n))
i' : Fin (n + 1)
⊢ get (scanl f (f b (head v)) (tail v)) (Fin.succ i') =
    f (get (b ::ᵥ scanl f (f b (head v)) (tail v)) (Fin.castSucc (Fin.succ i'))) (get (head v ::ᵥ tail v) (Fin.succ i'))

Next tactic:
simp only [hn, Fin.castSucc_fin_succ, get_cons_succ]
theorem mOfFn_pure {m} [Monad m] [LawfulMonad m] {α} :
    ∀ {n} (f : Fin n → α), (@mOfFn m _ _ _ fun i => pure (f i)) = pure (ofFn f)
  | 0, f => rfl
  | n + 1, f => by
    

Proof state:
n✝ : ℕ
α✝ : Type u_1
m : Type u_2 → Type u_3
inst✝¹ : Monad m
inst✝ : LawfulMonad m
α : Type u_2
n : ℕ
f : Fin (n + 1) → α
⊢ (mOfFn fun i => pure (f i)) = pure (ofFn f)

Next tactic:
rw [mOfFn, @mOfFn_pure m _ _ _ n _, ofFn]
theorem mOfFn_pure {m} [Monad m] [LawfulMonad m] {α} :
    ∀ {n} (f : Fin n → α), (@mOfFn m _ _ _ fun i => pure (f i)) = pure (ofFn f)
  | 0, f => rfl
  | n + 1, f => by
    rw [mOfFn, @mOfFn_pure m _ _ _ n _, ofFn]
    

Proof state:
n✝ : ℕ
α✝ : Type u_1
m : Type u_2 → Type u_3
inst✝¹ : Monad m
inst✝ : LawfulMonad m
α : Type u_2
n : ℕ
f : Fin (n + 1) → α
⊢ (do
      let a ← pure (f 0)
      let v ← pure (ofFn fun i => f (Fin.succ i))
      pure (a ::ᵥ v)) =
    pure (f 0 ::ᵥ ofFn fun i => f (Fin.succ i))

Next tactic:
simp
/-- Define `C v` by induction on `v : Vector α n`.

This function has two arguments: `h_nil` handles the base case on `C nil`,
and `h_cons` defines the inductive step using `∀ x : α, C w → C (x ::ᵥ w)`.

This can be used as `induction v using Vector.inductionOn`. -/
@[elab_as_elim]
def inductionOn {C : ∀ {n : ℕ}, Vector α n → Sort*} {n : ℕ} (v : Vector α n)
    (h_nil : C nil) (h_cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) : C v := by
  -- porting notes: removed `generalizing`: already generalized
  

Proof state:
n✝ : ℕ
α : Type u_1
C : {n : ℕ} → Vector α n → Sort u_2
n : ℕ
v : Vector α n
h_nil : C nil
h_cons : {n : ℕ} → {x : α} → {w : Vector α n} → C w → C (x ::ᵥ w)
⊢ C v

Next tactic:
induction' n with n ih