@@ -19,32 +19,39 @@ namespace List
1919for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
2020a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
2121@[elab_as_elim]
22- def reverseRecOn {motive : List α → Sort *} (l : List α) (nil : motive [])
23- (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) : motive l :=
24- match h : reverse l with
25- | [] => cast (congr_arg motive <| by simpa using congr(reverse $h.symm)) <|
26- nil
27- | head :: tail =>
28- cast (congr_arg motive <| by simpa using congr(reverse $h.symm)) <|
29- append_singleton _ head <| reverseRecOn (reverse tail) nil append_singleton
30- termination_by l.length
31- decreasing_by
32- simp_wf
33- rw [← length_reverse (as := l), h, length_cons]
34- simp
22+ def reverseRec {motive : List α → Sort *} (nil : motive [])
23+ (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) : ∀ l, motive l
24+ | [] => nil
25+ | a :: l => (dropLast_concat_getLast (cons_ne_nil a l)) ▸
26+ append_singleton _ _ ((a :: l).dropLast.reverseRec nil append_singleton)
27+ termination_by l => l.length
28+
29+ @[simp]
30+ theorem reverseRec_nil {motive : List α → Sort *} (nil : motive [])
31+ (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) :
32+ [].reverseRec nil append_singleton = nil := by grind [reverseRec]
3533
3634@[simp]
35+ theorem reverseRec_concat {motive : List α → Sort *} (x : α) (xs : List α) (nil : motive [])
36+ (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) :
37+ (xs ++ [x]).reverseRec nil append_singleton =
38+ append_singleton xs x (xs.reverseRec nil append_singleton) := by
39+ grind [reverseRec, cases List]
40+
41+ /-- Like `reverseRec`, but with the list parameter placed first. -/
42+ @[elab_as_elim]
43+ abbrev reverseRecOn {motive : List α → Sort *} (l : List α) (nil : motive [])
44+ (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) : motive l :=
45+ reverseRec nil append_singleton l
46+
3747theorem reverseRecOn_nil {motive : List α → Sort *} (nil : motive [])
3848 (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) :
39- reverseRecOn [] nil append_singleton = nil := reverseRecOn.eq_1 ..
49+ reverseRecOn [] nil append_singleton = nil := by simp
4050
41- -- `unusedHavesSuffices` is getting confused by the unfolding of `reverseRecOn`
42- @ [simp, nolint unusedHavesSuffices]
4351theorem reverseRecOn_concat {motive : List α → Sort *} (x : α) (xs : List α) (nil : motive [])
4452 (append_singleton : ∀ (l : List α) (a : α), motive l → motive (l ++ [a])) :
45- reverseRecOn (motive := motive) (xs ++ [x]) nil append_singleton =
46- append_singleton _ _ (reverseRecOn (motive := motive) xs nil append_singleton) := by
47- grind [reverseRecOn]
53+ (xs ++ [x]).reverseRecOn nil append_singleton =
54+ append_singleton xs x (reverseRecOn xs nil append_singleton) := by simp
4855
4956/-- Bidirectional induction principle for lists: if a property holds for the empty list, the
5057singleton list, and `a :: (l ++ [b])` from `l`, then it holds for all lists. This can be used to
@@ -57,25 +64,24 @@ def bidirectionalRec {motive : List α → Sort*} (nil : motive []) (singleton :
5764 | [] => nil
5865 | [a] => singleton a
5966 | a :: b :: l =>
60- let l' := dropLast (b :: l)
61- let b' := getLast (b :: l) (cons_ne_nil _ _)
62- cast (by rw [← dropLast_append_getLast (cons_ne_nil b l)]) <|
63- cons_append a l' b' (bidirectionalRec nil singleton cons_append l')
67+ (dropLast_concat_getLast (cons_ne_nil b l)) ▸
68+ cons_append a ((b :: l).dropLast) ((b :: l).getLast (cons_ne_nil _ _))
69+ ((b :: l).dropLast.bidirectionalRec nil singleton cons_append)
6470termination_by l => l.length
6571
6672@[simp]
6773theorem bidirectionalRec_nil {motive : List α → Sort *}
6874 (nil : motive []) (singleton : ∀ a : α, motive [a])
6975 (cons_append : ∀ (a : α) (l : List α) (b : α), motive l → motive (a :: (l ++ [b]))) :
70- bidirectionalRec nil singleton cons_append [] = nil := bidirectionalRec.eq_1 ..
76+ bidirectionalRec nil singleton cons_append [] = nil := by grind [bidirectionalRec]
7177
7278
7379@[simp]
7480theorem bidirectionalRec_singleton {motive : List α → Sort *}
7581 (nil : motive []) (singleton : ∀ a : α, motive [a])
7682 (cons_append : ∀ (a : α) (l : List α) (b : α), motive l → motive (a :: (l ++ [b]))) (a : α) :
7783 bidirectionalRec nil singleton cons_append [a] = singleton a := by
78- simp [bidirectionalRec]
84+ grind [bidirectionalRec]
7985
8086@[simp]
8187theorem bidirectionalRec_cons_append {motive : List α → Sort *}
@@ -84,8 +90,7 @@ theorem bidirectionalRec_cons_append {motive : List α → Sort*}
8490 (a : α) (l : List α) (b : α) :
8591 bidirectionalRec nil singleton cons_append (a :: (l ++ [b])) =
8692 cons_append a l b (bidirectionalRec nil singleton cons_append l) := by
87- conv_lhs => unfold bidirectionalRec
88- cases l with grind
93+ grind [bidirectionalRec, cases List]
8994
9095/-- Like `bidirectionalRec`, but with the list parameter placed first. -/
9196@[elab_as_elim]
0 commit comments