This PR adds lemmas about for loops over `Array`, following the existing lemmas for `List`.
159 lines
6.3 KiB
Text
159 lines
6.3 KiB
Text
/-
|
||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Kim Morrison
|
||
-/
|
||
prelude
|
||
import Init.Data.Array.Lemmas
|
||
import Init.Data.Array.Attach
|
||
import Init.Data.List.Monadic
|
||
|
||
/-!
|
||
# Lemmas about `Array.forIn'` and `Array.forIn`.
|
||
-/
|
||
|
||
namespace Array
|
||
|
||
open Nat
|
||
|
||
/-! ## Monadic operations -/
|
||
|
||
/-! ### mapM -/
|
||
|
||
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α → m β) (l : Array α) :
|
||
mapM f l = l.foldlM (fun acc a => return (acc.push (← f a))) #[] := by
|
||
rcases l with ⟨l⟩
|
||
simp only [List.mapM_toArray, bind_pure_comp, size_toArray, List.foldlM_toArray']
|
||
rw [List.mapM_eq_reverse_foldlM_cons]
|
||
simp only [bind_pure_comp, Functor.map_map]
|
||
suffices ∀ (k), (fun a => a.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) k l =
|
||
List.foldlM (fun acc a => acc.push <$> f a) k.reverse.toArray l by
|
||
exact this []
|
||
intro k
|
||
induction l generalizing k with
|
||
| nil => simp
|
||
| cons a as ih =>
|
||
simp [ih, List.foldlM_cons]
|
||
|
||
/-! ### foldlM and foldrM -/
|
||
|
||
theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : Array β₁) (init : α) :
|
||
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
|
||
cases l
|
||
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldlM_map]
|
||
|
||
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : Array β₁)
|
||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||
cases l
|
||
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldrM_map]
|
||
|
||
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : γ → β → m γ) (l : Array α) (init : γ) :
|
||
(l.filterMap f).foldlM g init =
|
||
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
|
||
cases l
|
||
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldlM_filterMap]
|
||
rfl
|
||
|
||
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : β → γ → m γ) (l : Array α) (init : γ) :
|
||
(l.filterMap f).foldrM g init =
|
||
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
|
||
cases l
|
||
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldrM_filterMap]
|
||
rfl
|
||
|
||
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : β → α → m β) (l : Array α) (init : β) :
|
||
(l.filter p).foldlM g init =
|
||
l.foldlM (fun x y => if p y then g x y else pure x) init := by
|
||
cases l
|
||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldlM_filter]
|
||
|
||
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β → m β) (l : Array α) (init : β) :
|
||
(l.filter p).foldrM g init =
|
||
l.foldrM (fun x y => if p x then g x y else pure y) init := by
|
||
cases l
|
||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldrM_filter]
|
||
|
||
/-! ### forIn' -/
|
||
|
||
/--
|
||
We can express a for loop over an array as a fold,
|
||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||
-/
|
||
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||
(l : Array α) (f : (a : α) → a ∈ l → β → m (ForInStep β)) (init : β) :
|
||
forIn' l init f = ForInStep.value <$>
|
||
l.attach.foldlM (fun b ⟨a, m⟩ => match b with
|
||
| .yield b => f a m b
|
||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||
cases l
|
||
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
|
||
simp only [List.forIn'_toArray, List.forIn'_eq_foldlM, List.attachWith_mem_toArray, size_toArray,
|
||
List.length_map, List.length_attach, List.foldlM_toArray', List.foldlM_map]
|
||
congr
|
||
|
||
/-- We can express a for loop over an array which always yields as a fold. -/
|
||
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||
(l : Array α) (f : (a : α) → a ∈ l → β → m γ) (g : (a : α) → a ∈ l → β → γ → β) (init : β) :
|
||
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
|
||
l.attach.foldlM (fun b ⟨a, m⟩ => g a m b <$> f a m b) init := by
|
||
cases l
|
||
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
|
||
simp [List.foldlM_map]
|
||
|
||
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||
(l : Array α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||
forIn' l init (fun a m b => pure (.yield (f a m b))) =
|
||
pure (f := m) (l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init) := by
|
||
cases l
|
||
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
|
||
|
||
@[simp] theorem forIn'_yield_eq_foldl
|
||
(l : Array α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||
cases l
|
||
simp [List.foldl_map]
|
||
|
||
/--
|
||
We can express a for loop over an array as a fold,
|
||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||
-/
|
||
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||
(f : α → β → m (ForInStep β)) (init : β) (l : Array α) :
|
||
forIn l init f = ForInStep.value <$>
|
||
l.foldlM (fun b a => match b with
|
||
| .yield b => f a b
|
||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||
cases l
|
||
simp only [List.forIn_toArray, List.forIn_eq_foldlM, size_toArray, List.foldlM_toArray']
|
||
congr
|
||
|
||
/-- We can express a for loop over an array which always yields as a fold. -/
|
||
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||
(l : Array α) (f : α → β → m γ) (g : α → β → γ → β) (init : β) :
|
||
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||
l.foldlM (fun b a => g a b <$> f a b) init := by
|
||
cases l
|
||
simp [List.foldlM_map]
|
||
|
||
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||
(l : Array α) (f : α → β → β) (init : β) :
|
||
forIn l init (fun a b => pure (.yield (f a b))) =
|
||
pure (f := m) (l.foldl (fun b a => f a b) init) := by
|
||
cases l
|
||
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
|
||
|
||
@[simp] theorem forIn_yield_eq_foldl
|
||
(l : Array α) (f : α → β → β) (init : β) :
|
||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||
l.foldl (fun b a => f a b) init := by
|
||
cases l
|
||
simp [List.foldl_map]
|
||
|
||
end Array
|