Theorem: Array.SatisfiesM_mapM
File: Std/Data/Array/Init/Lemmas.lean

tactic: unfold mapM
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
⊢ SatisfiesM (fun arr => motive (size as) ∧ ∃ eq, ∀ (i : Nat) (h : i < size as), p { val := i, isLt := h } arr[i])
    (mapM f as)

tactic: refine SatisfiesM_foldlM (m := m) (β := Array β)
  (motive := fun i arr => motive i ∧ arr.size = i ∧ ∀ i h2, p i (arr[i.1]'h2)) ?z ?s
  |>.imp fun ⟨h₁, eq, h₂⟩ => ⟨h₁, eq, fun _ _ => h₂ ..⟩
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
⊢ SatisfiesM (fun arr => motive (size as) ∧ ∃ eq, ∀ (i : Nat) (h : i < size as), p { val := i, isLt := h } arr[i])
    (foldlM
      (fun bs a => do
        let b ← f a
        pure (push bs b))
      (mkEmpty (size as)) as 0 (size as))

tactic: case z => exact ⟨h0, rfl, fun.⟩
state_before: case z
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
⊢ (fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]) 0
    (mkEmpty (size as))

tactic: exact ⟨h0, rfl, fun.⟩
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
⊢ (fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]) 0
    (mkEmpty (size as))

tactic: case s =>
intro ⟨i, hi⟩ arr ⟨ih₁, eq, ih₂⟩
refine (hs _ ih₁).bind fun b ⟨h₁, h₂⟩ => .pure ⟨h₂, by simp [eq], fun j hj => ?_⟩
simp [get_push] at hj ⊢; split; {apply ih₂}
cases j; cases (Nat.le_or_eq_of_le_succ hj).resolve_left ‹_›; cases eq; exact h₁
state_before: case s
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
⊢ ∀ (i : Fin (size as)) (b : Array β),
    (fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]) i.val b →
      SatisfiesM
        ((fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val])
          (i.val + 1))
        do
        let b_1 ← f as[i]
        pure (push b b_1)

tactic: intro ⟨i, hi⟩ arr ⟨ih₁, eq, ih₂⟩
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
⊢ ∀ (i : Fin (size as)) (b : Array β),
    (fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]) i.val b →
      SatisfiesM
        ((fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val])
          (i.val + 1))
        do
        let b_1 ← f as[i]
        pure (push b b_1)

tactic: refine (hs _ ih₁).bind fun b ⟨h₁, h₂⟩ => .pure ⟨h₂, by simp [eq], fun j hj => ?_⟩
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
⊢ SatisfiesM
    ((fun i arr => motive i ∧ size arr = i ∧ ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val])
      ({ val := i, isLt := hi }.val + 1))
    do
    let b ← f as[{ val := i, isLt := hi }]
    pure (push arr b)

tactic: simp [get_push] at hj ⊢
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
j : Fin (size as)
hj : j.val < size (push arr b)
⊢ p j (push arr b)[j.val]

tactic: split
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
j : Fin (size as)
hj : j.val < size arr + 1
⊢ p j (if h : j.val < size arr then arr[j.val] else b)

tactic: {apply ih₂}
state_before: case inl
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
j : Fin (size as)
hj : j.val < size arr + 1
h✝ : j.val < size arr
⊢ p j arr[j.val]

case inr
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
j : Fin (size as)
hj : j.val < size arr + 1
h✝ : ¬j.val < size arr
⊢ p j b

tactic: cases j
state_before: case inr
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
j : Fin (size as)
hj : j.val < size arr + 1
h✝ : ¬j.val < size arr
⊢ p j b

tactic: cases (Nat.le_or_eq_of_le_succ hj).resolve_left ‹_›
state_before: case inr.mk
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
val✝ : Nat
isLt✝ : val✝ < size as
hj : { val := val✝, isLt := isLt✝ }.val < size arr + 1
h✝ : ¬{ val := val✝, isLt := isLt✝ }.val < size arr
⊢ p { val := val✝, isLt := isLt✝ } b

tactic: cases eq
state_before: case inr.mk.refl
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
isLt✝ : List.length arr.data < size as
hj : { val := List.length arr.data, isLt := isLt✝ }.val < size arr + 1
h✝ : ¬{ val := List.length arr.data, isLt := isLt✝ }.val < size arr
⊢ p { val := List.length arr.data, isLt := isLt✝ } b

tactic: exact h₁
state_before: case inr.mk.refl.refl
m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
arr : Array β
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
isLt✝ : List.length arr.data < size as
hj : { val := List.length arr.data, isLt := isLt✝ }.val < size arr + 1
h✝ : ¬{ val := List.length arr.data, isLt := isLt✝ }.val < size arr
hi : List.length arr.data < size as
ih₁ : motive { val := List.length arr.data, isLt := hi }.val
x✝ : p { val := List.length arr.data, isLt := hi } b ∧ motive ({ val := List.length arr.data, isLt := hi }.val + 1)
h₁ : p { val := List.length arr.data, isLt := hi } b
h₂ : motive ({ val := List.length arr.data, isLt := hi }.val + 1)
⊢ p { val := List.length arr.data, isLt := isLt✝ } b

tactic: simp [eq]
state_before: m : Type u_1 → Type u_2
α : Type u_3
β : Type u_1
inst✝¹ : Monad m
inst✝ : LawfulMonad m
as : Array α
f : α → m β
motive : Nat → Prop
h0 : motive 0
p : Fin (size as) → β → Prop
hs : ∀ (i : Fin (size as)), motive i.val → SatisfiesM (fun x => p i x ∧ motive (i.val + 1)) (f as[i])
i : Nat
hi : i < size as
arr : Array β
ih₁ : motive { val := i, isLt := hi }.val
eq : size arr = { val := i, isLt := hi }.val
ih₂ : ∀ (i : Fin (size as)) (h2 : i.val < size arr), p i arr[i.val]
b : β
x✝ : p { val := i, isLt := hi } b ∧ motive ({ val := i, isLt := hi }.val + 1)
h₁ : p { val := i, isLt := hi } b
h₂ : motive ({ val := i, isLt := hi }.val + 1)
⊢ size (push arr b) = { val := i, isLt := hi }.val + 1