88prelude
99import Init.Data.Option.Basic
1010import Init.Data.Option.List
11+ import Init.Data.Option.Array
12+ import Init.Data.Array.Attach
1113import Init.Data.List.Attach
1214import Init.BinderPredicates
1315
1416namespace Option
1517
18+ instance {o : Option α} : Subsingleton { x // o = some x } where
19+ allEq a b := Subtype.ext (Option.some.inj (a.property.symm.trans b.property))
20+
1621/--
1722Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
1823`Option {x // P x}` is the same as the input `Option α`.
@@ -86,7 +91,7 @@ theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a,
8691 (o.attachWith p H).map Subtype.val = o :=
8792 (attachWith_map_val _ _ _).trans (congrFun Option.map_id _)
8893
89- theorem attach_eq_some : ∀ (o : Option a ) (x : {x // o = some x}), o.attach = some x
94+ theorem attach_eq_some : ∀ (o : Option α ) (x : {x // o = some x}), o.attach = some x
9095 | none, ⟨x, h⟩ => by simp at h
9196 | some a, ⟨x, h⟩ => by simpa using h
9297
@@ -123,20 +128,41 @@ theorem mem_attach : ∀ (o : Option α) (x : {x // o = some x}), x ∈ o.attach
123128 cases o <;> cases x <;> simp
124129
125130@[simp] theorem get_attach {o : Option α} (h : o.attach.isSome = true ) :
126- o.attach.get h = ⟨o.get (by simpa using h), by simp⟩ := by
127- cases o
128- · simp at h
129- · simp [get_some]
131+ o.attach.get h = ⟨o.get (by simpa using h), by simp⟩ :=
132+ Subsingleton.elim _ _
133+
134+ @[simp] theorem getD_attach {o : Option α} {fallback} :
135+ o.attach.getD fallback = fallback :=
136+ Subsingleton.elim _ _
137+
138+ @[simp] theorem get!_attach {o : Option α} [Inhabited { x // o = some x }] :
139+ o.attach.get! = default :=
140+ Subsingleton.elim _ _
130141
131142@[simp] theorem get_attachWith {p : α → Prop } {o : Option α} (H : ∀ a, o = some a → p a) (h : (o.attachWith p H).isSome) :
132143 (o.attachWith p H).get h = ⟨o.get (by simpa using h), H _ (by simp)⟩ := by
133- cases o
134- · simp at h
135- · simp [get_some]
144+ cases o <;> simp
145+
146+ @[simp] theorem getD_attachWith {p : α → Prop } {o : Option α} {h} {fallback} :
147+ (o.attachWith p h).getD fallback =
148+ ⟨o.getD fallback.1 , by cases o <;> (try exact fallback.2 ) <;> exact h _ (by simp)⟩ := by
149+ cases o <;> simp
136150
137151theorem toList_attach (o : Option α) :
138- o.attach.toList = o.toList.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
139- cases o <;> simp [toList]
152+ o.attach.toList = o.toList.attach.map fun x => ⟨x.1 , by simpa using x.2 ⟩ := by
153+ cases o <;> simp
154+
155+ theorem toList_attachWith {p : α → Prop } {o : Option α} {h} :
156+ (o.attachWith p h).toList = o.toList.attach.map fun x => ⟨x.1 , h _ (by simpa using x.2 )⟩ := by
157+ cases o <;> simp
158+
159+ theorem toArray_attach (o : Option α) :
160+ o.attach.toArray = o.toArray.attach.map fun x => ⟨x.1 , by simpa using x.2 ⟩ := by
161+ cases o <;> simp
162+
163+ theorem toArray_attachWith {p : α → Prop } {o : Option α} {h} :
164+ (o.attachWith p h).toArray = o.toArray.attach.map fun x => ⟨x.1 , h _ (by simpa using x.2 )⟩ := by
165+ cases o <;> simp
140166
141167@[simp, grind =] theorem attach_toList (o : Option α) :
142168 o.toList.attach = (o.attach.map fun ⟨a, h⟩ => ⟨a, by simpa using h⟩).toList := by
@@ -203,6 +229,11 @@ theorem attach_filter {o : Option α} {p : α → Bool} :
203229 · rintro ⟨h, rfl⟩
204230 simp [h]
205231
232+ theorem filter_attachWith {P : α → Prop } {o : Option α} {h : ∀ x, o = some x → P x} {q : α → Bool} :
233+ (o.attachWith P h).filter q =
234+ (o.filter q).attachWith P (fun _ h' => h _ (eq_some_of_filter_eq_some h')) := by
235+ cases o <;> simp [filter_some] <;> split <;> simp
236+
206237theorem filter_attach {o : Option α} {p : {x // o = some x} → Bool} :
207238 o.attach.filter p = o.pbind fun a h => if p ⟨a, h⟩ then some ⟨a, h⟩ else none := by
208239 cases o <;> simp [filter_some]
@@ -211,6 +242,64 @@ theorem toList_pbind {o : Option α} {f : (a : α) → o = some a → Option β}
211242 (o.pbind f).toList = o.attach.toList.flatMap (fun ⟨x, h⟩ => (f x h).toList) := by
212243 cases o <;> simp
213244
245+ theorem toArray_pbind {o : Option α} {f : (a : α) → o = some a → Option β} :
246+ (o.pbind f).toArray = o.attach.toArray.flatMap (fun ⟨x, h⟩ => (f x h).toArray) := by
247+ cases o <;> simp
248+
249+ theorem toList_pfilter {o : Option α} {p : (a : α) → o = some a → Bool} :
250+ (o.pfilter p).toList = (o.toList.attach.filter (fun x => p x.1 (by simpa using x.2 ))).unattach := by
251+ cases o with
252+ | none => simp
253+ | some a =>
254+ simp only [pfilter_some, toList_some, List.attach_cons, List.attach_nil, List.map_nil]
255+ split <;> rename_i h
256+ · rw [List.filter_cons_of_pos h]; simp
257+ · rw [List.filter_cons_of_neg h]; simp
258+
259+ theorem toArray_pfilter {o : Option α} {p : (a : α) → o = some a → Bool} :
260+ (o.pfilter p).toArray = (o.toArray.attach.filter (fun x => p x.1 (by simpa using x.2 ))).unattach := by
261+ cases o with
262+ | none => simp
263+ | some a =>
264+ simp only [pfilter_some, toArray_some, List.attach_toArray, List.attachWith_mem_toArray,
265+ List.attach_cons, List.attach_nil, List.map_nil, List.map_cons, List.size_toArray,
266+ List.length_cons, List.length_nil, Nat.zero_add, List.filter_toArray', List.unattach_toArray]
267+ split <;> rename_i h
268+ · rw [List.filter_cons_of_pos h]; simp
269+ · rw [List.filter_cons_of_neg h]; simp
270+
271+ theorem toList_pmap {p : α → Prop } {o : Option α} {f : (a : α) → p a → β}
272+ (h : ∀ a, o = some a → p a) :
273+ (o.pmap f h).toList = o.attach.toList.map (fun x => f x.1 (h _ x.2 )) := by
274+ cases o <;> simp
275+
276+ theorem toArray_pmap {p : α → Prop } {o : Option α} {f : (a : α) → p a → β}
277+ (h : ∀ a, o = some a → p a) :
278+ (o.pmap f h).toArray = o.attach.toArray.map (fun x => f x.1 (h _ x.2 )) := by
279+ cases o <;> simp
280+
281+ theorem attach_pfilter {o : Option α} {p : (a : α) → o = some a → Bool} :
282+ (o.pfilter p).attach =
283+ o.attach.pbind fun x h => if h' : p x (by simp_all) then
284+ some ⟨x.1 , by simpa [pfilter_eq_some_iff] using ⟨_, h'⟩⟩ else none := by
285+ cases o with
286+ | none => simp
287+ | some a =>
288+ simp only [attach_some, eq_mp_eq_cast, id_eq, pbind_some]
289+ rw [attach_congr pfilter_some]
290+ split <;> simp [*]
291+
292+ theorem attach_guard {p : α → Bool} {x : α} :
293+ (guard p x).attach = if h : p x then some ⟨x, by simp_all⟩ else none := by
294+ simp only [guard_eq_ite]
295+ split <;> simp [*]
296+
297+ theorem attachWith_guard {q : α → Bool} {x : α} {P : α → Prop }
298+ {h : ∀ a, guard q x = some a → P a} :
299+ (guard q x).attachWith P h = if h' : q x then some ⟨x, h _ (by simp_all)⟩ else none := by
300+ simp only [guard_eq_ite]
301+ split <;> simp [*]
302+
214303/-! ## unattach
215304
216305`Option.unattach` is the (one-sided) inverse of `Option.attach`. It is a synonym for `Option.map Subtype.val`.
@@ -255,6 +344,29 @@ def unattach {α : Type _} {p : α → Prop} (o : Option { x // p x }) := o.map
255344 (o.attachWith p H).unattach = o := by
256345 cases o <;> simp
257346
347+ theorem unattach_eq_some_iff {p : α → Prop } {o : Option { x // p x }} {x : α} :
348+ o.unattach = some x ↔ ∃ h, o = some ⟨x, h⟩ :=
349+ match o with
350+ | none => by simp
351+ | some ⟨y, h⟩ => by simpa using fun h' => h' ▸ h
352+
353+ @[simp]
354+ theorem unattach_eq_none_iff {p : α → Prop } {o : Option { x // p x }} :
355+ o.unattach = none ↔ o = none := by
356+ cases o <;> simp
357+
358+ theorem get_unattach {p : α → Prop } {o : Option { x // p x }} {h} :
359+ o.unattach.get h = (o.get (by simpa using h)).1 := by
360+ cases o <;> simp
361+
362+ theorem toList_unattach {p : α → Prop } {o : Option { x // p x }} :
363+ o.unattach.toList = o.toList.unattach := by
364+ cases o <;> simp
365+
366+ theorem toArray_unattach {p : α → Prop } {o : Option { x // p x }} :
367+ o.unattach.toArray = o.toArray.unattach := by
368+ cases o <;> simp
369+
258370/-! ### Recognizing higher order functions on subtypes using a function that only depends on the value. -/
259371
260372/--
@@ -279,4 +391,51 @@ and simplifies these to the function directly taking the value.
279391 · simp only [filter_some, hf, unattach_some]
280392 split <;> simp
281393
394+ @[simp] theorem unattach_guard {p : α → Prop } {q : { x // p x } → Bool} {r : α → Bool}
395+ (hq : ∀ x h, q ⟨x, h⟩ = r x) {x : { x // p x }} :
396+ (guard q x).unattach = guard r x.1 := by
397+ simp only [guard]
398+ split <;> simp_all
399+
400+ @[simp] theorem unattach_pfilter {p : α → Prop } {o : Option { x // p x }}
401+ {f : (a : { x // p x }) → o = some a → Bool}
402+ {g : (a : α) → o.unattach = some a → Bool} (hf : ∀ x h h', f ⟨x, h⟩ h' = g x (by simp_all)) :
403+ (o.pfilter f).unattach = o.unattach.pfilter g := by
404+ cases o with
405+ | none => simp
406+ | some a =>
407+ simp only [hf, pfilter_some, unattach_some]
408+ split <;> simp
409+
410+ @[simp] theorem unattach_merge {p : α → Prop } {f : { x // p x } → { x // p x } → { x // p x }}
411+ {g : α → α → α} (hf : ∀ x h y h', (f ⟨x, h⟩ ⟨y, h'⟩).1 = g x y) {o o' : Option { x // p x }} :
412+ (o.merge f o').unattach = o.unattach.merge g o'.unattach := by
413+ cases o <;> cases o' <;> simp [*]
414+
415+ theorem any_attach {p : α → Bool} {o : Option α} {q : { x // o = some x } → Bool}
416+ (h : ∀ x h, q ⟨x, h⟩ = p x) : o.attach.any q = o.any p := by
417+ cases o <;> simp [*]
418+
419+ theorem any_attachWith {p : α → Bool} {o : Option α} {r : α → Prop } (hr : ∀ x, o = some x → r x)
420+ {q : { x // r x } → Bool}
421+ (h : ∀ x h, q ⟨x, h⟩ = p x) : (o.attachWith r hr).any q = o.any p := by
422+ cases o <;> simp [*]
423+
424+ theorem any_unattach {p : α → Prop } {o : Option { x // p x }} {q : α → Bool} :
425+ o.unattach.any q = o.any (q ∘ Subtype.val) := by
426+ cases o <;> simp
427+
428+ theorem all_attach {p : α → Bool} {o : Option α} {q : { x // o = some x } → Bool}
429+ (h : ∀ x h, q ⟨x, h⟩ = p x) : o.attach.all q = o.all p := by
430+ cases o <;> simp [*]
431+
432+ theorem all_attachWith {p : α → Bool} {o : Option α} {r : α → Prop } (hr : ∀ x, o = some x → r x)
433+ {q : { x // r x } → Bool}
434+ (h : ∀ x h, q ⟨x, h⟩ = p x) : (o.attachWith r hr).all q = o.all p := by
435+ cases o <;> simp [*]
436+
437+ theorem all_unattach {p : α → Prop } {o : Option { x // p x }} {q : α → Bool} :
438+ o.unattach.all q = o.all (q ∘ Subtype.val) := by
439+ cases o <;> simp
440+
282441end Option
0 commit comments