11module
22
3- def parse_music : Unit :=
4- ()
3+ import Std.Data.HashMap.Lemmas
4+
5+ open Std
6+
7+ instance : LawfulHashable String.Slice := sorry -- will be in the next nightly
8+ instance : EquivBEq String.Slice := sorry
9+
10+ def parseMusic (musicString : String) : List Nat :=
11+ let noteMap : HashMap String.Slice Nat := .ofList [("o" , 4 ), ("o|" , 2 ), (".|" , 1 )]
12+ (musicString.split ' ' ).filterMap (noteMap[·]?) |>.toList
13+
14+ example : parseMusic "" = [] := by native_decide
15+ example : parseMusic "o o o o" = [4 , 4 , 4 , 4 ] := by native_decide
16+ example : parseMusic ".| .| .| .|" = [1 , 1 , 1 , 1 ] := by native_decide
17+ example : parseMusic "o| o| .| .| o o o o" = [2 , 2 , 1 , 1 , 4 , 4 , 4 , 4 ] := by native_decide
18+ example : parseMusic "o| .| o| .| o o| o o|" = [2 , 1 , 2 , 1 , 4 , 2 , 4 , 2 ] := by native_decide
19+
20+ def noteForValue (value : Nat) (h : value = 1 ∨ value = 2 ∨ value = 4 ) : String :=
21+ match value with
22+ | 0 => False.elim (by simp at h)
23+ | 1 => ".|"
24+ | 2 => "o|"
25+ | 3 => False.elim (by simp at h)
26+ | 4 => "o"
27+ | _ + 5 => False.elim (by simp at h)
28+
29+ def formatMusic (l : List Nat) (hl : ∀ value ∈ l, value = 1 ∨ value = 2 ∨ value = 4 ) : String :=
30+ " " .intercalate ((l.attachWith _ hl).map (fun p => noteForValue p.1 p.2 ))
31+
32+ @[simp]
33+ theorem String.copy_comp_toSlice : String.Slice.copy ∘ String.toSlice = id := by
34+ ext; simp
35+
36+ @[simp]
37+ theorem String.Slice.beq_list_iff {l l' : List String.Slice} : l == l' ↔ l.map String.Slice.copy = l'.map String.Slice.copy := by
38+ induction l generalizing l' with
39+ | nil => simp_all
40+ | cons => cases l' <;> simp_all
41+
42+ theorem String.toList_split_intercalate_beq {l : List String} (h : ∀ s ∈ l, ¬c ∈ s.toList) :
43+ (((String.singleton c).intercalate l).split c).toList ==
44+ if l = [] then ["" .toSlice] else l.map String.toSlice := by
45+ split <;> simp_all [String.toList_split_intercalate h]
46+
47+ theorem List.filterMap_beq_congr [BEq α] {l l' : List α} {f : α → Option β}
48+ (hf : ∀ a a', a == a' → f a = f a') (hl : l == l') : l.filterMap f = l'.filterMap f := by
49+ induction l generalizing l' with
50+ | nil => simp_all
51+ | cons h₁ t₁ ih =>
52+ match l' with
53+ | [] => simp_all
54+ | h₂ :: t₂ =>
55+ simp at hl
56+ simp [List.filterMap_cons, ih hl.2 , hf _ _ hl.1 ]
57+
58+ theorem parseMusic_formatMusic {l : List Nat} {hl} : parseMusic (formatMusic l hl) = l := by
59+ rw [parseMusic, formatMusic, Iter.toList_filterMap]
60+ -- TODO: use simproc from next nightly to avoid `erw`
61+ erw [List.filterMap_beq_congr (fun _ _ => HashMap.getElem?_congr) (String.toList_split_intercalate_beq _)]
62+ · simp
63+ by_cases hl : l = []
64+ · simp [hl]
65+ · simp [hl]
66+ clear hl
67+ induction l with
68+ | nil => simp
69+ | cons ht tl ih =>
70+ simp
71+ rw [List.filterMap_cons_some (b := ht)]
72+ · simp only [List.filterMap_map, List.cons.injEq, true_and]
73+ apply ih
74+ refine fun v hv => hl _ (by simp [hv])
75+ · simp
76+ obtain (rfl|rfl|rfl) := hl ht (by simp) <;>
77+ simp [noteForValue, HashMap.ofList_equiv_foldl.getElem_eq, HashMap.getElem_insert]
78+ · simp
79+ rintro _ val hval rfl
80+ obtain (rfl|rfl|rfl) := hl _ hval <;> simp [noteForValue]
581
682/-!
783## Prompt
@@ -25,7 +101,7 @@ def parse_music(music_string: str) -> List[int]:
25101 """
26102```
27103
28- ## Canonical solution
104+ ## Canonical soluton
29105
30106```python3
31107 note_map = {'o': 4, 'o|': 2, '.|': 1}
@@ -50,4 +126,4 @@ def check(candidate):
50126 assert candidate('o| o| .| .| o o o o') == [2, 2, 1, 1, 4, 4, 4, 4]
51127 assert candidate('o| .| o| .| o o| o o|') == [2, 1, 2, 1, 4, 2, 4, 2]
52128```
53- -/
129+ -/
0 commit comments