lean4-htt/src/Init/Data/Option/Attach.lean
2024-09-30 04:13:27 +00:00

178 lines
6.9 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) 2024 Lean FRO. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
prelude
import Init.Data.Option.Basic
import Init.Data.Option.List
import Init.Data.List.Attach
import Init.BinderPredicates
namespace Option
/--
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
`Option {x // P x}` is the same as the input `Option α`.
-/
@[inline] private unsafe def attachWithImpl
(o : Option α) (P : α → Prop) (_ : ∀ x ∈ o, P x) : Option {x // P x} := unsafeCast o
/-- "Attach" a proof `P x` that holds for the element of `o`, if present,
to produce a new option with the same element but in the type `{x // P x}`. -/
@[implemented_by attachWithImpl] def attachWith
(xs : Option α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Option {x // P x} :=
match xs with
| none => none
| some x => some ⟨x, H x (mem_some_self x)⟩
/-- "Attach" the proof that the element of `xs`, if present, is in `xs`
to produce a new option with the same elements but in the type `{x // x ∈ xs}`. -/
@[inline] def attach (xs : Option α) : Option {x // x ∈ xs} := xs.attachWith _ fun _ => id
@[simp] theorem attach_none : (none : Option α).attach = none := rfl
@[simp] theorem attachWith_none : (none : Option α).attachWith P H = none := rfl
@[simp] theorem attach_some {x : α} :
(some x).attach = some ⟨x, rfl⟩ := rfl
@[simp] theorem attachWith_some {x : α} {P : α → Prop} (h : ∀ (b : α), b ∈ some x → P b) :
(some x).attachWith P h = some ⟨x, by simpa using h⟩ := rfl
theorem attach_congr {o₁ o₂ : Option α} (h : o₁ = o₂) :
o₁.attach = o₂.attach.map (fun x => ⟨x.1, h ▸ x.2⟩) := by
subst h
simp
theorem attachWith_congr {o₁ o₂ : Option α} (w : o₁ = o₂) {P : α → Prop} {H : ∀ x ∈ o₁, P x} :
o₁.attachWith P H = o₂.attachWith P fun x h => H _ (w ▸ h) := by
subst w
simp
theorem attach_map_coe (o : Option α) (f : α → β) :
(o.attach.map fun (i : {i // i ∈ o}) => f i) = o.map f := by
cases o <;> simp
theorem attach_map_val (o : Option α) (f : α → β) :
(o.attach.map fun i => f i.val) = o.map f :=
attach_map_coe _ _
@[simp]
theorem attach_map_subtype_val (o : Option α) :
o.attach.map Subtype.val = o :=
(attach_map_coe _ _).trans (congrFun Option.map_id _)
theorem attachWith_map_coe {p : α → Prop} (f : α → β) (o : Option α) (H : ∀ a ∈ o, p a) :
((o.attachWith p H).map fun (i : { i // p i}) => f i.val) = o.map f := by
cases o <;> simp [H]
theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H : ∀ a ∈ o, p a) :
((o.attachWith p H).map fun i => f i.val) = o.map f :=
attachWith_map_coe _ _ _
@[simp]
theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a ∈ o, p a) :
(o.attachWith p H).map Subtype.val = o :=
(attachWith_map_coe _ _ _).trans (congrFun Option.map_id _)
@[simp] theorem mem_attach : ∀ (o : Option α) (x : {x // x ∈ o}), x ∈ o.attach
| none, ⟨x, h⟩ => by simp at h
| some a, ⟨x, h⟩ => by simpa using h
@[simp] theorem isNone_attach (o : Option α) : o.attach.isNone = o.isNone := by
cases o <;> simp
@[simp] theorem isNone_attachWith {p : α → Prop} (o : Option α) (H : ∀ a ∈ o, p a) :
(o.attachWith p H).isNone = o.isNone := by
cases o <;> simp
@[simp] theorem isSome_attach (o : Option α) : o.attach.isSome = o.isSome := by
cases o <;> simp
@[simp] theorem isSome_attachWith {p : α → Prop} (o : Option α) (H : ∀ a ∈ o, p a) :
(o.attachWith p H).isSome = o.isSome := by
cases o <;> simp
@[simp] theorem attach_eq_none_iff (o : Option α) : o.attach = none ↔ o = none := by
cases o <;> simp
@[simp] theorem attach_eq_some_iff {o : Option α} {x : {x // x ∈ o}} :
o.attach = some x ↔ o = some x.val := by
cases o <;> cases x <;> simp
@[simp] theorem attachWith_eq_none_iff {p : α → Prop} (o : Option α) (H : ∀ a ∈ o, p a) :
o.attachWith p H = none ↔ o = none := by
cases o <;> simp
@[simp] theorem attachWith_eq_some_iff {p : α → Prop} {o : Option α} (H : ∀ a ∈ o, p a) {x : {x // p x}} :
o.attachWith p H = some x ↔ o = some x.val := by
cases o <;> cases x <;> simp
@[simp] theorem get_attach {o : Option α} (h : o.attach.isSome = true) :
o.attach.get h = ⟨o.get (by simpa using h), by simp⟩ := by
cases o
· simp at h
· simp [get_some]
@[simp] theorem get_attachWith {p : α → Prop} {o : Option α} (H : ∀ a ∈ o, p a) (h : (o.attachWith p H).isSome) :
(o.attachWith p H).get h = ⟨o.get (by simpa using h), H _ (by simp)⟩ := by
cases o
· simp at h
· simp [get_some]
@[simp] theorem toList_attach (o : Option α) :
o.attach.toList = o.toList.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
cases o <;> simp
theorem attach_map {o : Option α} (f : α → β) :
(o.map f).attach = o.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
cases o <;> simp
theorem attachWith_map {o : Option α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), b ∈ o.map f → P b} :
(o.map f).attachWith P H = (o.attachWith (P ∘ f) (fun a h => H _ (mem_map_of_mem f h))).map
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
cases o <;> simp
theorem map_attach {o : Option α} (f : { x // x ∈ o } → β) :
o.attach.map f = o.pmap (fun a (h : a ∈ o) => f ⟨a, h⟩) (fun a h => h) := by
cases o <;> simp
theorem map_attachWith {o : Option α} {P : α → Prop} {H : ∀ (a : α), a ∈ o → P a}
(f : { x // P x } → β) :
(o.attachWith P H).map f =
o.pmap (fun a (h : a ∈ o ∧ P a) => f ⟨a, h.2⟩) (fun a h => ⟨h, H a h⟩) := by
cases o <;> simp
theorem attach_bind {o : Option α} {f : α → Option β} :
(o.bind f).attach =
o.attach.bind fun ⟨x, h⟩ => (f x).attach.map fun ⟨y, h'⟩ => ⟨y, mem_bind_iff.mpr ⟨x, h, h'⟩⟩ := by
cases o <;> simp
theorem bind_attach {o : Option α} {f : {x // x ∈ o} → Option β} :
o.attach.bind f = o.pbind fun a h => f ⟨a, h⟩ := by
cases o <;> simp
theorem pbind_eq_bind_attach {o : Option α} {f : (a : α) → a ∈ o → Option β} :
o.pbind f = o.attach.bind fun ⟨x, h⟩ => f x h := by
cases o <;> simp
theorem attach_filter {o : Option α} {p : α → Bool} :
(o.filter p).attach =
o.attach.bind fun ⟨x, h⟩ => if h' : p x then some ⟨x, by simp_all⟩ else none := by
cases o with
| none => simp
| some a =>
simp only [filter_some, attach_some]
ext
simp only [mem_def, attach_eq_some_iff, ite_none_right_eq_some, some.injEq, some_bind,
dite_none_right_eq_some]
constructor
· rintro ⟨h, w⟩
refine ⟨h, by ext; simpa using w⟩
· rintro ⟨h, rfl⟩
simp [h]
theorem filter_attach {o : Option α} {p : {x // x ∈ o} → Bool} :
o.attach.filter p = o.pbind fun a h => if p ⟨a, h⟩ then some ⟨a, h⟩ else none := by
cases o <;> simp [filter_some]
end Option