lean4-htt/src/Init/Data/Iterators/Lemmas/Consumers/Loop.lean
Markus Himmel ba0e755adc
feat: Std.Iter.first? (#12162)
This PR adds the function `Std.Iter.first?` and proves the specification
lemma `Std.Iter.first?_eq_match_step` if the iterator is productive.

The monadic variant on `Std.IterM` is also provided.

We use this new function to fix the default implementation for
`startsWith` and `dropPrefix` on `String` patterns, which used to fail
if the searcher returned a `skip` at the beginning. None of the patterns
we ship out of the box were affected by this, but user-defined patterns
were vulnerable.

---------

Co-authored-by: Paul Reichert <6992158+datokrat@users.noreply.github.com>
2026-01-27 12:10:16 +00:00

940 lines
41 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Iterators.Lemmas.Consumers.Collect
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
import all Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
import all Init.Data.Iterators.Consumers.Loop
import all Init.Data.Iterators.Consumers.Monadic.Collect
import Init.Data.Array.Monadic
public section
namespace Std
open Std.Iterators
theorem Iter.forIn'_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f =
IterM.DefaultConsumers.forIn' (n := m) (fun _ _ f x => f x.run) γ (fun _ _ _ => True)
it.toIterM init _ (fun _ => id)
(fun out h acc => return ⟨← f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc, trivial⟩) := by
simp only [instForIn', ForIn'.forIn', IteratorLoop.finiteForIn']
have : ∀ a b c, f a b c = (Subtype.val <$> (⟨·, trivial⟩) <$> f a b c) := by simp
simp +singlePass only [this]
rw [hl.lawful (fun _ _ f x => f x.run) (wf := IteratorLoop.wellFounded_of_finite)]
simp [IteratorLoop.defaultImplementation]
theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[hl : LawfulIteratorLoop α Id m] {γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (b : β) → γ → m (ForInStep γ)} :
ForIn.forIn it init f =
IterM.DefaultConsumers.forIn' (n := m) (fun _ _ f c => f c.run) γ (fun _ _ _ => True)
it.toIterM init _ (fun _ => id) (fun out _ acc => return ⟨← f out acc, trivial⟩) := by
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
@[congr] theorem Iter.forIn'_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
{ita itb : Iter (α := α) β} (w : ita = itb)
{b b' : γ} (hb : b = b')
{f : (a' : β) → _ → γ → m (ForInStep γ)}
{g : (a' : β) → _ → γ → m (ForInStep γ)}
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
forIn' ita b f = forIn' itb b' g := by
subst_eqs
simp only [← funext_iff] at h
rw [← h]
rfl
@[congr] theorem Iter.forIn_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
{ita itb : Iter (α := α) β} (w : ita = itb)
{b b' : γ} (hb : b = b')
{f : (a' : β) → γ → m (ForInStep γ)}
{g : (a' : β) → γ → m (ForInStep γ)}
(h : ∀ a b, f a b = g a b) :
forIn ita b f = forIn itb b' g := by
subst_eqs
simp only [← funext_iff] at h
rw [← h]
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
{γ : Type w} {it : Iter (α := α) β} {init : γ}
{f : (out : β) → _ → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f =
letI : ForIn' m (IterM (α := α) Id β) β _ := IterM.instForIn'
ForIn'.forIn' it.toIterM init
(fun out h acc => f out (isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
simp [ForIn'.forIn', Iter.instForIn', IterM.instForIn', monadLift]
theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m]
{γ : Type w} {it : Iter (α := α) β} {init : γ}
{f : β → γ → m (ForInStep γ)} :
ForIn.forIn it init f =
ForIn.forIn it.toIterM init f := by
simp [forIn_eq_forIn', forIn'_eq_forIn'_toIterM, -forIn'_eq_forIn]
theorem Iter.forIn'_eq_match_step {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) → _ → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f = (do
match it.step with
| .yield it' out h =>
match ← f out (.direct ⟨_, h⟩) init with
| .yield c =>
ForIn'.forIn' it' c
fun out h'' acc => f out (.indirect ⟨_, rfl, h⟩ h'') acc
| .done c => return c
| .skip it' h =>
ForIn'.forIn' it' init
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
| .done _ => return init) := by
simp only [forIn'_eq]
rw [IterM.DefaultConsumers.forIn'_eq_match_step (fun _ _ _ => True)
IteratorLoop.wellFounded_of_finite]
simp only [Iter.step]
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn
· simp only [IterM.Step.toPure_yield, PlausibleIterStep.yield, toIter_toIterM, toIterM_toIter,
bind_assoc]
apply bind_congr
intro forInStep
cases forInStep
· simp
· simp only [pure_bind]
apply IterM.DefaultConsumers.forIn'_eq_forIn' (fun _ _ _ => True)
IteratorLoop.wellFounded_of_finite
· simp
· simp only
apply IterM.DefaultConsumers.forIn'_eq_forIn' (fun _ _ _ => True)
IteratorLoop.wellFounded_of_finite
· simp
· simp
theorem Iter.forIn_eq_match_step {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : β → γ → m (ForInStep γ)} :
ForIn.forIn it init f = (do
match it.step with
| .yield it' out _ =>
match ← f out init with
| .yield c => ForIn.forIn it' c f
| .done c => return c
| .skip it' _ => ForIn.forIn it' init f
| .done _ => return init) := by
simp only [forIn_eq_forIn']
exact forIn'_eq_match_step
private theorem Iter.forIn'_toList.aux {ρ : Type u} {α : Type v} {γ : Type x} {m : Type x → Type x'}
[Monad m] {_ : Membership α ρ} [ForIn' m ρ α inferInstance]
{r s : ρ} {init : γ} {f : (a : α) → _ → γ → m (ForInStep γ)} (h : r = s) :
forIn' r init f = forIn' s init (fun a h' acc => f a (h ▸ h') acc) := by
cases h; rfl
theorem Iter.isPlausibleStep_iff_step_eq {α β} [Iterator α Id β]
[Finite α Id] [LawfulDeterministicIterator α Id]
{it : Iter (α := α) β} {step} :
it.IsPlausibleStep step ↔ it.step.val = step := by
obtain ⟨step', hs'⟩ := LawfulDeterministicIterator.isPlausibleStep_eq_eq (it := it.toIterM)
have hs := it.step.property
simp only [Iter.IsPlausibleStep, hs'] at hs
cases hs
simp only [IsPlausibleStep, hs', Iter.step, IterM.Step.toPure, toIter_toIterM,
IterStep.mapIterator_mapIterator, toIterM_comp_toIter, IterStep.mapIterator_id]
simp only [Eq.comm (b := step)]
constructor
· intro h
replace h := congrArg (IterStep.mapIterator IterM.toIter) h
simpa using h
· intro h
replace h := congrArg (IterStep.mapIterator Iter.toIterM) h
simpa using h
theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
[Finite α Id] [LawfulDeterministicIterator α Id]
{it : Iter (α := α) β} {out : β} :
out ∈ it.toList ↔ it.IsPlausibleIndirectOutput out := by
induction it using Iter.inductSteps with | step it ihy ihs
rw [toList_eq_match_step]
constructor
· intro h
cases heq : it.step using PlausibleIterStep.casesOn <;> simp only [heq] at h
· rename_i it' out hp
cases List.mem_cons.mp h <;> rename_i hmem
· cases hmem
simp only [Iter.IsPlausibleStep, IterStep.mapIterator_yield] at hp
exact Iter.IsPlausibleIndirectOutput.direct ⟨_, hp⟩
· apply Iter.IsPlausibleIndirectOutput.indirect
· exact ⟨_, rfl, _
· exact (ihy _).mp hmem
· apply Iter.IsPlausibleIndirectOutput.indirect
· exact ⟨_, rfl, _
· exact (ihs _).mp h
· cases h
· intro hp
cases hp
· rename_i hp
simp only [Iter.isPlausibleOutput_iff_exists, Iter.isPlausibleStep_iff_step_eq] at hp
obtain ⟨it', hp⟩ := hp
split <;> simp_all
· rename_i it' h₁ h₂
cases heq : it.step using PlausibleIterStep.casesOn <;> simp only
· apply List.mem_cons_of_mem
simp only [Iter.isPlausibleSuccessorOf_iff_exists, Iter.isPlausibleStep_iff_step_eq] at h₁
obtain ⟨step, h₁, rfl⟩ := h₁
simp only [heq, IterStep.successor, Option.some.injEq] at h₁
cases h₁
simp only [ihy _]
exact h₂
· simp only [Iter.isPlausibleSuccessorOf_iff_exists, Iter.isPlausibleStep_iff_step_eq] at h₁
obtain ⟨step, h₁, rfl⟩ := h₁
simp only [heq, IterStep.successor, Option.some.injEq] at h₁
cases h₁
rw [ihs _]
exact h₂
· simp only [Iter.isPlausibleSuccessorOf_iff_exists, Iter.isPlausibleStep_iff_step_eq] at h₁
obtain ⟨step, h₁, rfl⟩ := h₁
simp [heq, IterStep.successor] at h₁
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
[Finite α Id] [LawfulDeterministicIterator α Id]
{it : Iter (α := α) β} {out : β} :
out ∈ it.toArray ↔ it.IsPlausibleIndirectOutput out := by
rw [← Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) → _ → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it.toList init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toList_iff_isPlausibleIndirectOutput.mpr h) acc) := by
induction it using Iter.inductSteps generalizing init with | step it ihy ihs
have := it.toList_eq_match_step
generalize hs : it.step = step at this
rw [forIn'_toList.aux this]
rw [forIn'_eq_match_step]
rw [List.forIn'_eq_foldlM] at *
simp only [map_eq_pure_bind, hs]
cases step using PlausibleIterStep.casesOn
· rename_i it' out h
simp only [List.attach_cons, List.foldlM_cons, bind_pure_comp, map_bind]
apply bind_congr
intro forInStep
cases forInStep
· induction it'.toList.attach <;> simp [*]
· simp only [List.foldlM_map]
simp only [List.forIn'_eq_foldlM] at ihy
simp only at this
simp only [ihy h (f := fun out h acc => f out (by rw [this]; exact List.mem_cons_of_mem _ h) acc)]
· rename_i it' h
simp only [bind_pure_comp]
simp only [List.forIn'_eq_foldlM] at ihs
simp only at this
simp only [ihs h (f := fun out h acc => f out (this ▸ h) acc)]
· simp
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) → _ → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it.toArray init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mpr h) acc) := by
simp only [← Iter.toArray_toList (it := it), List.forIn'_toArray, Iter.forIn'_toList]
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) → _ → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f = ForIn'.forIn' it.toList init (fun out h acc => f out (Iter.mem_toList_iff_isPlausibleIndirectOutput.mp h) acc) := by
simp only [forIn'_toList]
congr
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) → _ → γ → m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
simp only [forIn'_toArray]
congr
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : β → γ → m (ForInStep γ)} :
ForIn.forIn it.toList init f = ForIn.forIn it init f := by
rw [List.forIn_eq_foldlM]
induction it using Iter.inductSteps generalizing init with | step it ihy ihs
rw [forIn_eq_match_step, Iter.toList_eq_match_step]
simp only [map_eq_pure_bind]
generalize it.step = step
cases step using PlausibleIterStep.casesOn
· rename_i it' out h
simp only [List.foldlM_cons, bind_pure_comp, map_bind]
apply bind_congr
intro forInStep
cases forInStep
· induction it'.toList <;> simp [*]
· simp only [ForIn.forIn] at ihy
simp [ihy h]
· rename_i it' h
simp only [bind_pure_comp]
rw [ihs h]
· simp
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : β → γ → m (ForInStep γ)} :
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
simp only [← Iter.toArray_toList, List.forIn_toArray, forIn_toList]
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
{init : γ} {it : Iter (α := α) β} :
it.foldM (init := init) f = ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x) :=
(rfl)
theorem Iter.foldM_eq_foldM_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m]
{γ : Type w} {it : Iter (α := α) β} {init : γ} {f : γ → β → m γ} :
it.foldM (init := init) f = it.toIterM.foldM (init := init) f := by
simp [foldM_eq_forIn, IterM.foldM_eq_forIn, forIn_eq_forIn_toIterM]
theorem Iter.forIn_yield_eq_foldM {α β : Type w} {γ : Type x} {δ : Type x} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[LawfulIteratorLoop α Id m] {f : β → γ → m δ} {g : β → γ → δ → γ} {init : γ}
{it : Iter (α := α) β} :
ForIn.forIn (m := m) it init (fun c b => (fun d => .yield (g c b d)) <$> f c b) =
it.foldM (m := m) (fun b c => g c b <$> f c b) init := by
simp [Iter.foldM_eq_forIn]
theorem Iter.foldM_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[LawfulIteratorLoop α Id m] {f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
it.foldM (init := init) f = (do
match it.step with
| .yield it' out _ => it'.foldM (init := ← f init out) f
| .skip it' _ => it'.foldM (init := init) f
| .done _ => return init) := by
rw [Iter.foldM_eq_forIn, Iter.forIn_eq_match_step]
generalize it.step = step
cases step using PlausibleIterStep.casesOn <;> simp [foldM_eq_forIn]
theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[LawfulIteratorLoop α Id m]
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
it.toList.foldlM (init := init) f = it.foldM (init := init) f:= by
rw [foldM_eq_forIn, ← Iter.forIn_toList]
simp
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[LawfulIteratorLoop α Id m]
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toArray]
simp only [Array.forIn_yield_eq_foldlM, id_map']
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : β → γ → m (ForInStep γ)} :
forIn it init f = ForInStep.value <$>
it.foldM (fun c b => match c with
| .yield c => f b c
| .done c => pure (.done c)) (ForInStep.yield init) := by
simp only [← Iter.forIn_toList, List.forIn_eq_foldlM, ← Iter.foldlM_toList]; rfl
theorem Iter.fold_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f =
(ForIn.forIn (m := Id) it init (fun x acc => pure (ForInStep.yield (f acc x)))).run := by
rfl
theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
simp [foldM_eq_forIn, fold_eq_forIn]
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id]
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
@[simp]
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β → γγ} {init : γ}
{it : Iter (α := α) β} :
ForIn.forIn (m := Id) it init (fun c b => pure (.yield (f c b))) =
pure (it.fold (fun b c => f c b) init) := by
simp only [fold_eq_forIn]
rfl
theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f = (match it.step with
| .yield it' out _ => it'.fold (init := f init out) f
| .skip it' _ => it'.fold (init := init) f
| .done _ => init) := by
rw [fold_eq_foldM, foldM_eq_match_step]
simp only [fold_eq_foldM]
generalize it.step = step
cases step using PlausibleIterStep.casesOn <;> simp
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
theorem Iter.fold_hom {γ₁ : Type x₁} {γ₂ : Type x₂} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id.{x₁}] [LawfulIteratorLoop α Id Id.{x₁}]
[IteratorLoop α Id Id.{x₂}] [LawfulIteratorLoop α Id Id.{x₂}]
{it : Iter (α := α) β}
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
it.fold g₂ (f init) = f (it.fold g₁ init) := by
-- We cannot reduce to `IterM.fold_hom` because `IterM.fold` is necessarily more restrictive
-- w.r.t. the universe of the output.
induction it using Iter.inductSteps generalizing init with | step it ihy ihs =>
rw [fold_eq_match_step, fold_eq_match_step]
split
· rw [H, ihy _]
· rw [ihs _]
· simp
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
simp only [← toArray_toList, toList_eq_fold]
rw [← fold_hom (List.toArray)]
simp
@[simp]
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
it.toList.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, List.foldl_eq_foldlM, ← Iter.foldlM_toList]
@[simp]
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
theorem Iter.count_eq_count_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id.{w}] {it : Iter (α := α) β} :
it.count = it.toIterM.count.run.down :=
(rfl)
theorem Iter.count_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
{it : Iter (α := α) β} :
it.count = it.fold (γ := Nat) (init := 0) (fun acc _ => acc + 1) := by
rw [count_eq_count_toIterM, IterM.count_eq_fold, ← fold_eq_fold_toIterM]
rw [← fold_hom (f := ULift.down)]
simp
theorem Iter.count_eq_forIn {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
{it : Iter (α := α) β} :
it.count = (ForIn.forIn (m := Id) it 0 (fun _ acc => return .yield (acc + 1))).run := by
rw [count_eq_fold, forIn_pure_yield_eq_fold, Id.run_pure]
theorem Iter.count_eq_match_step {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.count = (match it.step.val with
| .yield it' _ => it'.count + 1
| .skip it' => it'.count
| .done => 0) := by
simp only [count_eq_count_toIterM]
rw [IterM.count_eq_match_step]
simp only [bind_pure_comp, id_map', Id.run_bind, Iter.step]
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
@[simp]
theorem Iter.size_toArray_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.toArray.size = it.count := by
simp only [toArray_eq_toArray_toIterM, count_eq_count_toIterM, Id.run_map,
← IterM.up_size_toArray_eq_count]
@[deprecated Iter.size_toArray_eq_count (since := "2025-10-29")]
def Iter.size_toArray_eq_size := @size_toArray_eq_count
@[simp]
theorem Iter.length_toList_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.toList.length = it.count := by
rw [← toList_toArray, Array.length_toList, size_toArray_eq_count]
@[deprecated Iter.length_toList_eq_count (since := "2025-10-29")]
def Iter.length_toList_eq_size := @length_toList_eq_count
@[simp]
theorem Iter.length_toListRev_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.toListRev.length = it.count := by
rw [toListRev_eq, List.length_reverse, length_toList_eq_count]
@[deprecated Iter.length_toListRev_eq_count (since := "2025-10-29")]
def Iter.length_toListRev_eq_size := @length_toListRev_eq_count
theorem Iter.anyM_eq_forIn {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.anyM p = (ForIn.forIn it false (fun x _ => do
if ← p x then
return .done true
else
return .yield false)) := by
rfl
theorem Iter.anyM_eq_match_step {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.anyM p = (do
match it.step.val with
| .yield it' x =>
if (← p x) then
return true
else
it'.anyM p
| .skip it' => it'.anyM p
| .done => return false) := by
rw [anyM_eq_forIn, forIn_eq_match_step]
simp only [bind_assoc]
cases it.step using PlausibleIterStep.casesOn
· apply bind_congr; intro px
split
· simp
· simp [anyM_eq_forIn]
· simp [anyM_eq_forIn]
· simp
theorem Iter.anyM_toList {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.toList.anyM p = it.anyM p := by
induction it using Iter.inductSteps with | step it ihy ihs =>
rw [it.toList_eq_match_step, anyM_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only [List.anyM_cons, ihy _]
· simp only [ihs _]
· simp only [List.anyM_nil]
theorem Iter.anyM_toArray {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.toArray.anyM p = it.anyM p := by
simp only [← Iter.toArray_toList, List.anyM_toArray, anyM_toList]
theorem Iter.any_eq_anyM {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.any p = (it.anyM (fun x => pure (f := Id) (p x))).run := by
rfl
theorem Iter.anyM_pure {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.anyM (fun x => pure (f := Id) (p x)) = pure (it.any (fun x => p x)) := by
simp [any_eq_anyM]
theorem Iter.any_eq_match_step {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.any p = (match it.step.val with
| .yield it' x =>
if p x then
true
else
it'.any p
| .skip it' => it'.any p
| .done => false) := by
rw [any_eq_anyM, anyM_eq_match_step]
split
· simp only [pure_bind, Bool.if_true_left, Bool.decide_eq_true, any_eq_anyM]
split <;> simp [*]
· simp [any_eq_anyM]
· simp
theorem Iter.any_eq_forIn {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.any p = (ForIn.forIn (m := Id) it false (fun x _ => do
if p x then
return .done true
else
return .yield false)).run := by
simp [any_eq_anyM, anyM_eq_forIn]
theorem Iter.any_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.toList.any p = it.any p := by
induction it using Iter.inductSteps with | step it ihy ihs =>
rw [it.toList_eq_match_step, any_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only [List.any_cons, ihy _]
split <;> simp [*]
· simp only [ihs _]
· simp only [List.any_nil]
theorem Iter.any_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.toArray.any p = it.any p := by
simp only [← Iter.toArray_toList, List.any_toArray, any_toList]
theorem Iter.allM_eq_forIn {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.allM p = (ForIn.forIn it true (fun x _ => do
if ← p x then
return .yield true
else
return .done false)) := by
rfl
theorem Iter.allM_eq_match_step {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.allM p = (do
match it.step.val with
| .yield it' x =>
if (← p x) then
it'.allM p
else
return false
| .skip it' => it'.allM p
| .done => return true) := by
rw [allM_eq_forIn, forIn_eq_match_step]
simp only [bind_assoc]
cases it.step using PlausibleIterStep.casesOn
· apply bind_congr; intro px
split
· simp [allM_eq_forIn]
· simp
· simp [allM_eq_forIn]
· simp
theorem Iter.all_eq_allM {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.all p = (it.allM (fun x => pure (f := Id) (p x))).run := by
rfl
theorem Iter.allM_pure {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.allM (fun x => pure (f := Id) (p x)) = pure (it.all (fun x => p x)) := by
simp [all_eq_allM]
theorem Iter.all_eq_match_step {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.all p = (match it.step.val with
| .yield it' x =>
if p x then
it'.all p
else
false
| .skip it' => it'.all p
| .done => true) := by
rw [all_eq_allM, allM_eq_match_step]
split
· simp only [pure_bind, all_eq_allM, Bool.if_false_right, Bool.decide_eq_true]
split <;> simp [*]
· simp [all_eq_allM]
· simp
theorem Iter.all_eq_forIn {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.all p = (ForIn.forIn (m := Id) it true (fun x _ => do
if p x then
return .yield true
else
return .done false)).run := by
simp [all_eq_allM, allM_eq_forIn]
theorem Iter.all_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.toList.all p = it.all p := by
induction it using Iter.inductSteps with | step it ihy ihs =>
rw [it.toList_eq_match_step, all_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only [List.all_cons, ihy _]
split <;> simp [*]
· simp only [ihs _]
· simp only [List.all_nil]
theorem Iter.all_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.toArray.all p = it.all p := by
simp only [← Iter.toArray_toList, List.all_toArray, all_toList]
theorem Iter.allM_eq_not_anyM_not {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {p : β → m Bool} :
it.allM p = (! ·) <$> it.anyM ((! ·) <$> p ·) := by
induction it using Iter.inductSteps with | step it ihy ihs =>
rw [allM_eq_match_step, anyM_eq_match_step, map_eq_pure_bind]
cases it.step using PlausibleIterStep.casesOn
· simp only [map_eq_pure_bind, bind_assoc, pure_bind]
apply bind_congr; intro px
split
· simp [*, ihy _]
· simp [*]
· simp [ihs _]
· simp
theorem Iter.all_eq_not_any_not {α β : Type w} [Iterator α Id β]
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {p : β → Bool} :
it.all p = ! it.any (! p ·) := by
induction it using Iter.inductSteps with | step it ihy ihs =>
rw [all_eq_match_step, any_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only
split
· simp [*, ihy _]
· simp [*]
· simp [ihs _]
· simp
theorem Iter.findSomeM?_eq_match_step {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m] [LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {f : β → m (Option γ)} :
it.findSomeM? f = (do
match it.step.val with
| .yield it' out =>
match ← f out with
| none => it'.findSomeM? f
| some fx => return (some fx)
| .skip it' => it'.findSomeM? f
| .done => return none) := by
rw [findSomeM?, forIn_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only [bind_assoc]
apply bind_congr; intro fx
split <;> simp [findSomeM?]
· simp [findSomeM?]
· simp
theorem Iter.findSomeM?_toList {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m]
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {f : β → m (Option γ)} :
it.toList.findSomeM? f = it.findSomeM? f := by
induction it using Iter.inductSteps with | step it ihy ihs
rw [it.findSomeM?_eq_match_step, it.toList_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only [List.findSomeM?_cons]
apply bind_congr; intro fx
split <;> simp [ihy _]
· simp [ihs _]
· simp
theorem Iter.findSome?_eq_findSomeM? {α β : Type w} {γ : Type x}
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
{it : Iter (α := α) β} {f : β → Option γ} :
it.findSome? f = Id.run (it.findSomeM? (pure <| f ·)) :=
(rfl)
theorem Iter.findSome?_eq_findSome?_toIterM {α β γ : Type w}
[Iterator α Id β] [IteratorLoop α Id Id.{w}] [Finite α Id]
{it : Iter (α := α) β} {f : β → Option γ} :
it.findSome? f = (it.toIterM.findSome? f).run :=
(rfl)
theorem Iter.findSome?_eq_match_step {α β : Type w} {γ : Type x}
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
[LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} {f : β → Option γ} :
it.findSome? f = (match it.step.val with
| .yield it' out =>
match f out with
| none => it'.findSome? f
| some fx => some fx
| .skip it' => it'.findSome? f
| .done => none) := by
rw [findSome?_eq_findSomeM?, findSomeM?_eq_match_step]
split
· simp only [pure_bind, findSome?_eq_findSomeM?]
split <;> simp
· simp [findSome?_eq_findSomeM?]
· simp
theorem Iter.findSome?_toList {α β : Type w} {γ : Type x}
[Iterator α Id β] [IteratorLoop α Id Id]
[Finite α Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {f : β → Option γ} :
it.toList.findSome? f = it.findSome? f := by
simp [findSome?_eq_findSomeM?, List.findSome?_eq_findSomeM?, findSomeM?_toList]
theorem Iter.findSomeM?_pure {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m] [IteratorLoop α Id Id]
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {f : β → Option γ} :
it.findSomeM? (pure <| f ·) = pure (f := m) (it.findSome? f) := by
simp [← findSomeM?_toList, ← findSome?_toList, List.findSomeM?_pure]
theorem Iter.findM?_eq_findSomeM? {α β : Type w} {m : Type w → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
it.findM? f = it.findSomeM? (fun x => return if (← f x).down then some x else none) :=
(rfl)
theorem Iter.findM?_eq_match_step {α β : Type w} {m : Type w → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m] [LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
it.findM? f = (do
match it.step.val with
| .yield it' out =>
if (← f out).down then return (some out) else it'.findM? f
| .skip it' => it'.findM? f
| .done => return none) := by
rw [findM?_eq_findSomeM?, findSomeM?_eq_match_step]
split
· simp only [bind_assoc]
apply bind_congr; intro fx
split <;> simp [findM?_eq_findSomeM?]
· simp [findM?_eq_findSomeM?]
· simp
theorem Iter.findM?_toList {α β : Type} {m : Type → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m]
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {f : β → m Bool} :
it.toList.findM? f = it.findM? (.up <$> f ·) := by
simp [findM?_eq_findSomeM?, List.findM?_eq_findSomeM?, findSomeM?_toList]
theorem Iter.findM?_eq_findM?_toList {α β : Type} {m : Type → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m]
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
it.findM? f = it.toList.findM? (ULift.down <$> f ·) := by
simp [findM?_toList]
theorem Iter.find?_eq_findM? {α β : Type w} [Iterator α Id β]
[IteratorLoop α Id Id] [Finite α Id] {it : Iter (α := α) β} {f : β → Bool} :
it.find? f = Id.run (it.findM? (pure <| .up <| f ·)) :=
(rfl)
theorem Iter.find?_eq_find?_toIterM {α β : Type w} [Iterator α Id β]
[IteratorLoop α Id Id] [Finite α Id] {it : Iter (α := α) β} {f : β → Bool} :
it.find? f = (it.toIterM.find? f).run :=
(rfl)
theorem Iter.find?_eq_findSome? {α β : Type w} [Iterator α Id β]
[IteratorLoop α Id Id] [Finite α Id] {it : Iter (α := α) β} {f : β → Bool} :
it.find? f = it.findSome? (fun x => if f x then some x else none) := by
simp [find?_eq_findM?, findSome?_eq_findSomeM?, findM?_eq_findSomeM?]
theorem Iter.find?_eq_match_step {α β : Type w}
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {f : β → Bool} :
it.find? f = (match it.step.val with
| .yield it' out =>
if f out then some out else it'.find? f
| .skip it' => it'.find? f
| .done => none) := by
rw [find?_eq_findM?, findM?_eq_match_step]
split
· simp only [pure_bind]
split <;> simp [find?_eq_findM?]
· simp [find?_eq_findM?]
· simp
theorem Iter.find?_toList {α β : Type w}
[Iterator α Id β] [IteratorLoop α Id Id]
[Finite α Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {f : β → Bool} :
it.toList.find? f = it.find? f := by
simp [find?_eq_findSome?, List.find?_eq_findSome?_guard, findSome?_toList, Option.guard_def]
theorem Iter.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
[Iterator α Id β] [IteratorLoop α Id m] [IteratorLoop α Id Id]
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β} {f : β → ULift Bool} :
it.findM? (pure (f := m) <| f ·) = pure (f := m) (it.find? (ULift.down <| f ·)) := by
induction it using Iter.inductSteps with | step it ihy ihs
rw [findM?_eq_match_step, find?_eq_match_step]
cases it.step using PlausibleIterStep.casesOn
· simp only [pure_bind]
split
· simp
· simp [ihy _]
· simp [ihs _]
· simp
theorem Iter.first?_eq_first?_toIterM {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
{it : Iter (α := α) β} :
it.first? = it.toIterM.first?.run := (rfl)
theorem Iter.first?_eq_match_step {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
[Productive α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
it.first? = match it.step.val with
| .yield _ out => some out
| .skip it' => it'.first?
| .done => none := by
rw [Iter.first?_eq_first?_toIterM, IterM.first?_eq_match_step]
simp only [Id.run_bind, step]
generalize it.toIterM.step.run.inflate = s
rcases s with ⟨_|_|_, _⟩ <;> simp [Iter.first?_eq_first?_toIterM]
theorem Iter.first?_eq_head?_toList {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
[Finite α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
it.first? = it.toList.head? := by
induction it using Iter.inductSteps with | step it ihy ihs
rw [first?_eq_match_step, toList_eq_match_step]
cases it.step using PlausibleIterStep.casesOn <;> simp [*]
end Std