feat: complete addition of @[grind] annotations for Option (#8216)

This PR completes adding `@[grind]` annotations for `Option` lemmas, and
incidentally fills in some `Option` API gaps/defects.
This commit is contained in:
Kim Morrison 2025-05-04 03:14:25 +10:00 committed by GitHub
parent 6e2e1a4f89
commit 80349ac77b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 167 additions and 141 deletions

View file

@ -195,7 +195,7 @@ theorem attach_filter {o : Option α} {p : α → Bool} :
| some a =>
simp only [filter_some, attach_some]
ext
simp only [attach_eq_some_iff, ite_none_right_eq_some, some.injEq, some_bind,
simp only [attach_eq_some_iff, ite_none_right_eq_some, some.injEq, bind_some,
dite_none_right_eq_some]
constructor
· rintro ⟨h, w⟩

View file

@ -13,11 +13,20 @@ namespace Option
deriving instance DecidableEq for Option
deriving instance BEq for Option
@[simp, grind] theorem getD_none : getD none a = a := rfl
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind] theorem map_none (f : α → β) : none.map f = none := rfl
@[simp, grind] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
def getM [Alternative m] : Option α → m α
| none => failure
| some a => pure a
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
/-- Returns `true` on `some x` and `false` on `none`. -/
@[inline] def isSome : Option α → Bool
| some _ => true
@ -75,6 +84,14 @@ Examples:
| none, _ => none
| some a, f => f a
@[simp, grind] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
@[simp, grind] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
@[deprecated bind_none (since := "2025-05-03")]
abbrev none_bind := @bind_none
@[deprecated bind_some (since := "2025-05-03")]
abbrev some_bind := @bind_some
/--
Runs the monadic action `f` on `o`'s value, if any, and returns the result, or `none` if there is
no value.
@ -102,6 +119,9 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
| none => pure none
| some x => some <$> f x
@[simp, grind] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
/--
Applies a function in some applicative functor to an optional value, returning `none` with no
effects if the value is missing.
@ -111,6 +131,10 @@ This is an alias for `Option.mapM`, which already works for applicative functors
@[inline] protected def mapA [Applicative m] (f : α → m β) : Option α → m (Option β) :=
Option.mapM f
/-- For verification purposes, we replace `mapA` with `mapM`. -/
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
@[simp, grind]
theorem map_id : (Option.map id : Option α → Option α) = id :=
funext (fun o => match o with | none => rfl | some _ => rfl)
@ -142,6 +166,9 @@ Examples:
| some a => p a
| none => true
@[simp, grind] theorem all_none : Option.all p none = true := rfl
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
/--
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
@ -154,6 +181,9 @@ Examples:
| some a => p a
| none => false
@[simp, grind] theorem any_none : Option.any p none = false := rfl
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
/--
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
`some a`, otherwise evaluates and returns the second argument.
@ -164,6 +194,9 @@ See also `or` for a version that is strict in the second argument.
| some a, _ => some a
| none, b => b ()
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
instance : OrElse (Option α) where
orElse := Option.orElse
@ -230,15 +263,6 @@ def merge (fn : ααα) : Option α → Option α → Option α
| none , some y => some y
| some x, some y => some <| fn x y
@[simp, grind] theorem getD_none : getD none a = a := rfl
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind] theorem map_none (f : α → β) : none.map f = none := rfl
@[simp, grind] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
@[simp, grind] theorem none_bind (f : α → Option β) : none.bind f = none := rfl
@[simp, grind] theorem some_bind (a) (f : α → Option β) : (some a).bind f = f a := rfl
/--
A case analysis function for `Option`.
@ -262,9 +286,9 @@ Extracts the value from an option that can be proven to be `some`.
@[inline] def get {α : Type u} : (o : Option α) → isSome o → α
| some x, _ => x
@[simp] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
@[simp, grind] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
| some _, _ => rfl
@[simp] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
/--
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
@ -342,6 +366,9 @@ Examples:
-/
@[simp, inline] def join (x : Option (Option α)) : Option α := x.bind id
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
@[simp, grind] theorem join_some : (some o).join = o := rfl
/--
Converts an optional monadic computation into a monadic computation of an optional value.
@ -363,7 +390,10 @@ some "world"
-/
@[inline] def sequence [Applicative m] {α : Type u} : Option (m α) → m (Option α)
| none => pure none
| some fn => some <$> fn
| some f => some <$> f
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
@[simp, grind] theorem sequence_some [Applicative m] (f : m (Option α)) : (some f).sequence = some <$> f := rfl
/--
A monadic case analysis function for `Option`.
@ -388,6 +418,9 @@ This is the monadic analogue of `Option.getD`.
| some a => pure a
| none => y
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
rfl {x} :=
match x with
@ -400,12 +433,6 @@ instance (α) [BEq α] [LawfulBEq α] : LawfulBEq (Option α) where
| some x, some y => rw [LawfulBEq.eq_of_beq (α := α) h]
| none, none => rfl
@[simp, grind] theorem all_none : Option.all p none = true := rfl
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
@[simp, grind] theorem any_none : Option.any p none = false := rfl
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
/--
The minimum of two optional values, with `none` treated as the least element. This function is
usually accessed through the `Min (Option α)` instance, rather than directly.
@ -428,10 +455,10 @@ protected def min [Min α] : Option α → Option α → Option α
instance [Min α] : Min (Option α) where min := Option.min
@[simp] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp] theorem min_some_none [Min α] {a : α} : min (some a) none = none := rfl
@[simp] theorem min_none_some [Min α] {b : α} : min none (some b) = none := rfl
@[simp] theorem min_none_none [Min α] : min (none : Option α) none = none := rfl
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp, grind] theorem min_some_none [Min α] {a : α} : min (some a) none = none := rfl
@[simp, grind] theorem min_none_some [Min α] {b : α} : min none (some b) = none := rfl
@[simp, grind] theorem min_none_none [Min α] : min (none : Option α) none = none := rfl
/--
The maximum of two optional values.
@ -453,10 +480,10 @@ protected def max [Max α] : Option α → Option α → Option α
instance [Max α] : Max (Option α) where max := Option.max
@[simp] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp] theorem max_some_none [Max α] {a : α} : max (some a) none = some a := rfl
@[simp] theorem max_none_some [Max α] {b : α} : max none (some b) = some b := rfl
@[simp] theorem max_none_none [Max α] : max (none : Option α) none = none := rfl
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp, grind] theorem max_some_none [Max α] {a : α} : max (some a) none = some a := rfl
@[simp, grind] theorem max_none_some [Max α] {b : α} : max none (some b) = some b := rfl
@[simp, grind] theorem max_none_none [Max α] : max (none : Option α) none = none := rfl
end Option
@ -481,6 +508,7 @@ instance : Alternative Option where
failure := Option.none
orElse := Option.orElse
-- This is a duplicate of `Option.getM`; one may be deprecated in the future.
def liftOption [Alternative m] : Option α → m α
| some a => pure a
| none => failure

View file

@ -12,7 +12,7 @@ universe u v
namespace Option
theorem eq_of_eq_some {α : Type u} : ∀ {x y : Option α}, (∀z, x = some z ↔ y = some z) → x = y
theorem eq_of_eq_some {α : Type u} : ∀ {x y : Option α}, (∀ z, x = some z ↔ y = some z) → x = y
| none, none, _ => rfl
| none, some z, h => Option.noConfusion ((h z).2 rfl)
| some z, none, h => Option.noConfusion ((h z).1 rfl)

View file

@ -180,9 +180,9 @@ abbrev ball_ne_none := @forall_ne_none
@[simp] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
@[simp] theorem bind_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp] theorem bind_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
@[simp] theorem bind_fun_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
cases x <;> rfl
theorem bind_eq_some_iff : x.bind f = some b ↔ ∃ a, x = some a ∧ f a = some b := by
@ -295,21 +295,21 @@ theorem map_congr {x : Option α} (h : ∀ a, x = some a → f a = g a) :
x.map f = x.map g := by
cases x <;> simp only [map_none, map_some, h]
@[simp] theorem map_id_fun {α : Type u} : Option.map (id : αα) = id := by
@[simp, grind] theorem map_id_fun {α : Type u} : Option.map (id : αα) = id := by
funext; simp [map_id]
theorem map_id' {x : Option α} : (x.map fun a => a) = x := congrFun map_id x
@[simp] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
@[simp, grind] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
funext; simp [map_id']
theorem get_map {f : α → β} {o : Option α} {h : (o.map f).isSome} :
@[simp, grind] theorem get_map {f : α → β} {o : Option α} {h : (o.map f).isSome} :
(o.map f).get h = f (o.get (by simpa using h)) := by
cases o with
| none => simp at h
| some a => simp
@[simp] theorem map_map (h : β → γ) (g : α → β) (x : Option α) :
@[simp, grind _=_] theorem map_map (h : β → γ) (g : α → β) (x : Option α) :
(x.map g).map h = x.map (h ∘ g) := by
cases x <;> simp only [map_none, map_some, ·∘·]
@ -381,12 +381,12 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
x.filter p = x.bind (Option.guard p) := by
cases x <;> rfl
@[simp] theorem all_guard (a : α) :
@[simp, grind] theorem all_guard (a : α) :
Option.all q (guard p a) = (!p a || q a) := by
simp only [guard]
split <;> simp_all
@[simp] theorem any_guard (a : α) : Option.any q (guard p a) = (p a && q a) := by
@[simp, grind] theorem any_guard (a : α) : Option.any q (guard p a) = (p a && q a) := by
simp only [guard]
split <;> simp_all
@ -432,26 +432,28 @@ theorem any_map {α β : Type _} {x : Option α} {f : α → β} {p : β → Boo
theorem bind_map_comm {α β} {x : Option (Option α)} {f : α → β} :
x.bind (Option.map f) = (x.map (Option.map f)).bind id := by cases x <;> simp
theorem bind_map {f : α → β} {g : β → Option γ} {x : Option α} :
@[grind] theorem bind_map {f : α → β} {g : β → Option γ} {x : Option α} :
(x.map f).bind g = x.bind (g ∘ f) := by cases x <;> simp
@[simp] theorem map_bind {f : α → Option β} {g : β → γ} {x : Option α} :
@[simp, grind] theorem map_bind {f : α → Option β} {g : β → γ} {x : Option α} :
(x.bind f).map g = x.bind (Option.map g ∘ f) := by cases x <;> simp
theorem join_map_eq_map_join {f : α → β} {x : Option (Option α)} :
@[grind] theorem join_map_eq_map_join {f : α → β} {x : Option (Option α)} :
(x.map (Option.map f)).join = x.join.map f := by cases x <;> simp
theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join).join := by
@[grind _=_] theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join).join := by
cases x <;> simp
theorem mem_of_mem_join {a : α} {x : Option (Option α)} (h : a ∈ x.join) : some a ∈ x :=
h.symm ▸ join_eq_some_iff.1 h
@[simp, grind] theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
@[deprecated orElse_some (since := "2025-05-03")]
theorem some_orElse (a : α) (f) : (some a).orElse f = some a := rfl
@[simp, grind] theorem none_orElse (f : Unit → Option α) : none.orElse f = f () := rfl
@[deprecated orElse_none (since := "2025-05-03")]
theorem none_orElse (f : Unit → Option α) : none.orElse f = f () := rfl
@[simp] theorem orElse_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
@[simp] theorem orElse_fun_none (x : Option α) : x.orElse (fun _ => none) = x := by cases x <;> rfl
theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
(o.orElse f) = some x ↔ o = some x o = none ∧ f () = some x := by
@ -460,7 +462,7 @@ theorem orElse_eq_some_iff (o : Option α) (f) (x : α) :
theorem orElse_eq_none_iff (o : Option α) (f) : (o.orElse f) = none ↔ o = none ∧ f () = none := by
cases o <;> simp
theorem map_orElse {x : Option α} {y} :
@[grind]theorem map_orElse {x : Option α} {y} :
(x.orElse y).map f = (x.map f).orElse (fun _ => (y ()).map f) := by
cases x <;> simp
@ -504,7 +506,7 @@ theorem guard_comp {p : α → Bool} {f : β → α} :
ext1 b
simp [guard]
theorem bind_guard (x : Option α) (p : α → Bool) :
@[grind] theorem bind_guard (x : Option α) (p : α → Bool) :
x.bind (Option.guard p) = x.filter p := by
simp only [Option.filter_eq_bind, decide_eq_true_eq]
@ -599,9 +601,11 @@ abbrev choice_isSome_iff_nonempty := @isSome_choice_iff_nonempty
end choice
@[simp, grind] theorem toList_some (a : α) : (some a).toList = [a] := rfl
@[simp, grind] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
@[simp, grind] theorem toArray_some (a : α) : (some a).toArray = #[a] := rfl
@[simp, grind] theorem toArray_none (α : Type _) : (none : Option α).toArray = #[] := rfl
-- See `Init.Data.Option.List` for lemmas about `toList`.
@[simp, grind] theorem some_or : (some a).or o = some a := rfl
@ -637,7 +641,7 @@ abbrev or_eq_none := @or_eq_none_iff
@[deprecated or_eq_some_iff (since := "2025-04-10")]
abbrev or_eq_some := @or_eq_some_iff
theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
@[grind] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
cases o₁ <;> cases o₂ <;> rfl
instance : Std.Associative (or (α := α)) := ⟨@or_assoc _⟩
@ -685,10 +689,14 @@ section beq
variable [BEq α]
@[simp] theorem none_beq_none : ((none : Option α) == none) = true := rfl
@[simp] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
@[simp] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
@[simp] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
@[simp, grind] theorem none_beq_none : ((none : Option α) == none) = true := rfl
@[simp, grind] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
@[simp, grind] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
@[simp, grind] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
/-- We simplify away `isEqSome` in terms of `==`. -/
@[simp, grind] theorem isEqSome_eq_beq_some {o : Option α} : isEqSome o y = (o == some y) := by
cases o <;> simp [isEqSome]
@[simp] theorem reflBEq_iff : ReflBEq (Option α) ↔ ReflBEq α := by
constructor
@ -802,14 +810,14 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
end ite
theorem isSome_filter {α : Type _} {x : Option α} {f : α → Bool} :
@[grind] theorem isSome_filter {α : Type _} {x : Option α} {f : α → Bool} :
(x.filter f).isSome = x.any f := by
cases x
· rfl
· rw [Bool.eq_iff_iff]
simp only [Option.any_some, Option.filter, Option.isSome_ite]
@[simp] theorem get_filter {α : Type _} {x : Option α} {f : α → Bool} (h : (x.filter f).isSome) :
@[simp, grind] theorem get_filter {α : Type _} {x : Option α} {f : α → Bool} (h : (x.filter f).isSome) :
(x.filter f).get h = x.get (isSome_of_isSome_filter f x h) := by
cases x
· contradiction
@ -821,11 +829,11 @@ theorem isSome_filter {α : Type _} {x : Option α} {f : α → Bool} :
@[simp, grind] theorem pbind_none : pbind none f = none := rfl
@[simp, grind] theorem pbind_some : pbind (some a) f = f a rfl := rfl
@[simp] theorem map_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
@[simp, grind] theorem map_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
{g : β → γ} : (o.pbind f).map g = o.pbind (fun a h => (f a h).map g) := by
cases o <;> rfl
@[simp] theorem pbind_map {α β γ : Type _} (o : Option α)
@[simp, grind] theorem pbind_map {α β γ : Type _} (o : Option α)
(f : α → β) (g : (x : β) → o.map f = some x → Option γ) :
(o.map f).pbind g = o.pbind (fun x h => g (f x) (h ▸ rfl)) := by
cases o <;> rfl
@ -895,11 +903,11 @@ theorem pmap_eq_map (p : α → Prop) (f : α → β) (o : Option α) (H) :
@pmap _ _ p (fun a _ => f a) o H = Option.map f o := by
cases o <;> simp
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H) :
@[grind] theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H) :
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
cases o <;> simp
theorem pmap_map (o : Option α) (f : α → β) {p : β → Prop} (g : ∀ b, p b → γ) (H) :
@[grind] theorem pmap_map (o : Option α) (f : α → β) {p : β → Prop} (g : ∀ b, p b → γ) (H) :
pmap g (o.map f) H =
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some_iff.2 ⟨_, m, rfl⟩)) := by
cases o <;> simp
@ -941,7 +949,7 @@ theorem pmap_congr {α : Type u} {β : Type v}
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
cases o <;> simp
@[simp] theorem elim_pmap {p : α → Prop} (f : (a : α) → p a → β) (o : Option α)
@[simp, grind] theorem elim_pmap {p : α → Prop} (f : (a : α) → p a → β) (o : Option α)
(H : ∀ (a : α), o = some a → p a) (g : γ) (g' : β → γ) :
(o.pmap f H).elim g g' =
o.pelim g (fun a h => g' (f a (H a h))) := by
@ -978,7 +986,7 @@ theorem isSome_of_isSome_pfilter {α : Type _} {o : Option α} {p : (a : α) →
(h : (o.pfilter p).isSome) : o.isSome :=
(isSome_pfilter_iff_get.mp h).1
@[simp] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) → o = some a → Bool}
@[simp, grind] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) → o = some a → Bool}
(h : (o.pfilter p).isSome) :
(o.pfilter p).get h = o.get (isSome_of_isSome_pfilter h) := by
cases o <;> simp

View file

@ -10,62 +10,38 @@ import Init.Data.List.Lemmas
namespace Option
@[simp] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
cases o <;> simp [eq_comm]
@[simp] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
forIn' none b f = pure b := by
rfl
@[simp] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
cases o <;> rfl
@[simp] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
forIn o.toList b f = forIn o b f := by
cases o <;> rfl
@[simp] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
o.toList.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp] theorem foldr_toList (o : Option β) (a : α) (f : β → αα) :
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β → αα) :
o.toList.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp
@[simp]
@[simp, grind]
theorem pairwise_toList {P : αα → Prop} {o : Option α} : o.toList.Pairwise P := by
cases o <;> simp
@[simp]
@[simp, grind]
theorem head?_toList {o : Option α} : o.toList.head? = o := by
cases o <;> simp

View file

@ -12,16 +12,47 @@ import Init.Control.Lawful.Basic
namespace Option
@[simp] theorem forM_none [Monad m] (f : α → m PUnit) :
none.forM f = pure .unit := rfl
@[simp, grind] theorem bindM_none [Monad m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
@[simp, grind] theorem bindM_some [Monad m] [LawfulMonad m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
simp [Option.bindM]
@[simp] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
(some a).forM f = f a := rfl
-- We simplify `Option.forM` to `forM`.
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
@[simp] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
(o.map g).forM f = o.forM (fun a => f (g a)) := by
@[simp, grind] theorem forM_none [Monad m] (f : α → m PUnit) :
forM none f = pure .unit := rfl
@[simp, grind] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
forM (some a) f = f a := rfl
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
forM (o.map g) f = forM o (fun a => f (g a)) := by
cases o <;> simp
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
forIn' none b f = pure b := by
rfl
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
congr
funext x
split <;> rfl
@[congr] theorem forIn'_congr [Monad m] [LawfulMonad m] {as bs : Option α} (w : as = bs)
{b b' : β} (hb : b = b')
{f : (a' : α) → a' ∈ as → β → m (ForInStep β)}
@ -60,7 +91,7 @@ theorem forIn'_eq_pelim [Monad m] [LawfulMonad m]
o.pelim b (fun a h => f a h b) := by
cases o <;> simp
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α → β) (f : (b : β) → b ∈ o.map g → γ → m (ForInStep γ)) :
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases o <;> simp
@ -89,11 +120,9 @@ theorem forIn_eq_elim [Monad m] [LawfulMonad m]
o.elim b (fun a => f a b) := by
cases o <;> simp
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
cases o <;> simp
@[simp] theorem mapA_eq_mapM : @Option.mapA = @Option.mapM := rfl
end Option

View file

@ -4495,10 +4495,10 @@ theorem getEntry?_filterMap' [BEq α] [EquivBEq α]
specialize hf ⟨k', v⟩
split
· rename_i h
simp only [List.filterMap_cons, Option.some_bind]
simp only [List.filterMap_cons, Option.bind_some]
simp only [containsKey_congr h] at hl
split
· simp only [ih, f _ = _, Option.none_bind, getEntry?_eq_none.mpr hl.2]
· simp only [ih, f _ = _, Option.bind_none, getEntry?_eq_none.mpr hl.2]
· rw [f _ = _, Option.all_some, BEq.congr_right h] at hf
rw [getEntry?_cons, hf, f _ = _, cond_true]
· simp only [List.filterMap_cons]
@ -5169,7 +5169,7 @@ theorem getValue?_filterMap_of_getKey?_eq_some {β : Type v} {γ : Type w} [BEq
simp only [getKey?_eq_getEntry?, Option.map_eq_some_iff, getValue?_eq_getEntry?,
getEntry?_filterMap distinct, Option.map_bind, forall_exists_index, and_imp]
intro x hx hk
simp only [hx, Option.some_bind, Function.comp_apply, hk, Option.map_map, Option.map_some]
simp only [hx, Option.bind_some, Function.comp_apply, hk, Option.map_map, Option.map_some]
cases f k' x.2 <;> simp
theorem getValue!_filterMap {β : Type v} {γ : Type w} [BEq α] [EquivBEq α] [Inhabited γ]

View file

@ -1,36 +0,0 @@
/-!
This file contains WIP notes about potential further `grind` attributes for `Option`.
-/
attribute [grind] Option.some_get Option.get_some
attribute [grind] Option.map_map -- `[grind _=_]`?
attribute [grind] Option.get_map -- ??
attribute [grind] Option.map_id_fun Option.map_id_fun'
attribute [grind] Option.all_guard Option.any_guard
attribute [grind] Option.bind_map Option.map_bind
attribute [grind] Option.join_map_eq_map_join
attribute [grind] Option.join_join -- `[grind _=_]`?
attribute [grind] Option.map_orElse
-- Look again at `Option.guard` lemmas, consider `bind_gaurd`.
-- Fix statement of `isSome_guard`, add `isNone_guard`
attribute [grind] Option.or_assoc -- unless `grind` gains native associativity support in the meantime!
-- attribute [grind] Option.none_beq_none -- warning: this generates just `none` as the pattern!
-- attribute [grind] Option.none_beq_some
-- attribute [grind] Option.some_beq_none -- warning: this generates just `some _` as the pattern!
-- attribute [grind] Option.some_beq_some
attribute [grind] Option.isSome_filter
attribute [grind] Option.get_filter Option.get_pfilter
attribute [grind] Option.map_pbind Option.pbind_map
attribute [grind] Option.map_pmap Option.pmap_map Option.elim_pmap
-- Lemmas about inequalities?
-- The `min_none_none` family of lemmas result in grind issues:
-- failed to synthesize instance when instantiating Option.min_none_none
-- Min α

View file

@ -0,0 +1,21 @@
-- This file uses `#guard_msgs` to check which lemmas `grind` is using.
-- This may prove fragile, so remember it is okay to update the expected output if appropriate!
-- Hopefully these will act as regression tests against `grind` activating irrelevant lemmas.
set_option grind.warning false
variable [BEq α] {o₁ o₂ o₃ o₄ o₅ : Option α}
/--
info: Try this: grind only [Option.some_or, Option.or_some', Option.or_assoc, Option.some_beq_none]
-/
#guard_msgs in
example : ((o₁.or (o₂.or (some x))).or (o₄.or o₅) == none) = false := by grind?
/-- info: Try this: grind only [= Nat.min_def, Option.max_some_none, Option.min_some_some] -/
#guard_msgs in
example : max (some 7) none = min (some 13) (some 7) := by grind?
/-- info: Try this: grind only [Option.guard_pos] -/
#guard_msgs in
example : Option.guard (· ≤ 7) 3 = some 3 := by grind? [Option.guard_pos]