This PR adds `cbv` annotations to some iterator and string operations. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
78 lines
2.6 KiB
Text
78 lines
2.6 KiB
Text
/-
|
|
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Author: Markus Himmel
|
|
-/
|
|
module
|
|
|
|
prelude
|
|
public import Init.Data.String.Modify
|
|
import all Init.Data.String.Modify
|
|
import Init.Data.String.Lemmas.Basic
|
|
|
|
/-!
|
|
# Lemmas for `Init.Data.String.Modify`
|
|
|
|
This file contains lemmas for the operations defined in `Init.Data.String.Modify`.
|
|
|
|
Note that `Init.Data.String.Modify` already proves a few lemmas which are needed immediately.
|
|
-/
|
|
|
|
public section
|
|
|
|
namespace String
|
|
|
|
/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
|
theorem Pos.Splits.pastSet {s : String} {p : s.Pos} {t₁ t₂ : String}
|
|
{c d : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
|
|
(p.pastSet d h.ne_endPos_of_singleton).Splits (t₁ ++ singleton d) t₂ := by
|
|
generalize h.ne_endPos_of_singleton = hp
|
|
obtain ⟨rfl, rfl, rfl⟩ := by simpa using h.eq (p.splits_next_right hp)
|
|
apply splits_pastSet
|
|
|
|
/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
|
|
theorem Pos.Splits.pastModify {s : String} {p : s.Pos} {t₁ t₂ : String}
|
|
{c : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
|
|
(p.pastModify f h.ne_endPos_of_singleton).Splits
|
|
(t₁ ++ singleton (f (p.get h.ne_endPos_of_singleton))) t₂ :=
|
|
h.pastSet
|
|
|
|
theorem toList_mapAux {f : Char → Char} {s : String} {p : s.Pos}
|
|
(h : p.Splits t₁ t₂) : (mapAux f s p).toList = t₁.toList ++ t₂.toList.map f := by
|
|
fun_induction mapAux generalizing t₁ t₂ with
|
|
| case1 s => simp_all
|
|
| case2 s p hp ih =>
|
|
obtain ⟨c, rfl⟩ := h.exists_eq_singleton_append hp
|
|
simp [ih h.pastModify]
|
|
|
|
@[simp]
|
|
theorem toList_map {f : Char → Char} {s : String} : (s.map f).toList = s.toList.map f := by
|
|
simp [map, toList_mapAux s.splits_startPos]
|
|
|
|
/-
|
|
Used internally by the `cbv` tactic.
|
|
-/
|
|
@[cbv_eval]
|
|
theorem map_eq_internal {f : Char → Char} {s : String} : s.map f = .ofList (s.toList.map f) := by
|
|
apply String.toList_injective
|
|
simp only [toList_map, toList_ofList]
|
|
|
|
@[simp]
|
|
theorem length_map {f : Char → Char} {s : String} : (s.map f).length = s.length := by
|
|
simp [← length_toList]
|
|
|
|
@[simp]
|
|
theorem map_eq_empty {f : Char → Char} {s : String} : s.map f = "" ↔ s = "" := by
|
|
simp [← toList_eq_nil_iff]
|
|
|
|
@[simp]
|
|
theorem map_map {f g : Char → Char} {s : String} : String.map g (String.map f s) = String.map (g ∘ f) s := by
|
|
apply String.ext
|
|
simp [List.map_map]
|
|
|
|
@[simp]
|
|
theorem map_id {s : String} : String.map id s = s := by
|
|
apply String.ext
|
|
simp [List.map_id]
|
|
|
|
end String
|