@@ -854,6 +854,10 @@ begin
854
854
{ simpa }
855
855
end
856
856
857
+ @[simp] lemma modify_head_modify_head (l : list α) (f g : α → α) :
858
+ (l.modify_head f).modify_head g = l.modify_head (g ∘ f) :=
859
+ by cases l; simp
860
+
857
861
/-! ### Induction from the right -/
858
862
859
863
/-- Induction principle from the right for lists: if a property holds for the empty list, and
@@ -2456,12 +2460,17 @@ end mfoldl_mfoldr
2456
2460
2457
2461
/-! ### split_at and split_on -/
2458
2462
2463
+ section split_at_on
2464
+ variables (p : α → Prop ) [decidable_pred p] (xs ys : list α)
2465
+ (ls : list (list α)) (f : list α → list α)
2466
+
2459
2467
@[simp] theorem split_at_eq_take_drop : ∀ (n : ℕ) (l : list α), split_at n l = (take n l, drop n l)
2460
2468
| 0 a := rfl
2461
2469
| (succ n) [] := rfl
2462
2470
| (succ n) (x :: xs) := by simp only [split_at, split_at_eq_take_drop n xs, take, drop]
2463
2471
2464
2472
@[simp] lemma split_on_nil {α : Type u} [decidable_eq α] (a : α) : [].split_on a = [[]] := rfl
2473
+ @[simp] lemma split_on_p_nil : [].split_on_p p = [[]] := rfl
2465
2474
2466
2475
/-- An auxiliary definition for proving a specification lemma for `split_on_p`.
2467
2476
@@ -2474,22 +2483,20 @@ def split_on_p_aux' {α : Type u} (P : α → Prop) [decidable_pred P] : list α
2474
2483
if P h then xs :: split_on_p_aux' t []
2475
2484
else split_on_p_aux' t (xs ++ [h])
2476
2485
2477
- lemma split_on_p_aux_eq {α : Type u} (P : α → Prop ) [decidable_pred P] (xs ys : list α) :
2478
- split_on_p_aux' P xs ys = split_on_p_aux P xs ((++) ys) :=
2486
+ lemma split_on_p_aux_eq : split_on_p_aux' p xs ys = split_on_p_aux p xs ((++) ys) :=
2479
2487
begin
2480
2488
induction xs with a t ih generalizing ys; simp! only [append_nil, eq_self_iff_true, and_self],
2481
2489
split_ifs; rw ih,
2482
2490
{ refine ⟨rfl, rfl⟩ },
2483
2491
{ congr, ext, simp }
2484
2492
end
2485
2493
2486
- lemma split_on_p_aux_nil {α : Type u} (P : α → Prop ) [decidable_pred P] (xs : list α) :
2487
- split_on_p_aux P xs id = split_on_p_aux' P xs [] :=
2494
+ lemma split_on_p_aux_nil : split_on_p_aux p xs id = split_on_p_aux' p xs [] :=
2488
2495
by { rw split_on_p_aux_eq, refl }
2489
2496
2490
2497
/-- The original list `L` can be recovered by joining the lists produced by `split_on_p p L`,
2491
2498
interspersed with the elements `L.filter p`. -/
2492
- lemma split_on_p_spec {α : Type u} (p : α → Prop ) [decidable_pred p] (as : list α) :
2499
+ lemma split_on_p_spec (as : list α) :
2493
2500
join (zip_with (++) (split_on_p p as) ((as.filter p).map (λ x, [x]) ++ [[]])) = as :=
2494
2501
begin
2495
2502
rw [split_on_p, split_on_p_aux_nil],
@@ -2500,6 +2507,68 @@ begin
2500
2507
split_ifs; simp [zip_with, join, *],
2501
2508
end
2502
2509
2510
+ lemma split_on_p_aux_ne_nil : split_on_p_aux p xs f ≠ [] :=
2511
+ begin
2512
+ induction xs with _ _ ih generalizing f, { trivial, },
2513
+ simp only [split_on_p_aux], split_ifs, { trivial, }, exact ih _,
2514
+ end
2515
+
2516
+ lemma split_on_p_aux_spec : split_on_p_aux p xs f = (xs.split_on_p p).modify_head f :=
2517
+ begin
2518
+ simp only [split_on_p],
2519
+ induction xs with hd tl ih generalizing f, { simp [split_on_p_aux], },
2520
+ simp only [split_on_p_aux], split_ifs, { simp, },
2521
+ rw [ih (λ l, f (hd :: l)), ih (λ l, id (hd :: l))],
2522
+ simp,
2523
+ end
2524
+
2525
+ lemma split_on_p_ne_nil : xs.split_on_p p ≠ [] := split_on_p_aux_ne_nil _ _ id
2526
+
2527
+ @[simp] lemma split_on_p_cons (x : α) (xs : list α) :
2528
+ (x :: xs).split_on_p p =
2529
+ if p x then [] :: xs.split_on_p p else (xs.split_on_p p).modify_head (cons x) :=
2530
+ by { simp only [split_on_p, split_on_p_aux], split_ifs, { simp }, rw split_on_p_aux_spec, refl, }
2531
+
2532
+ /-- If no element satisfies `p` in the list `xs`, then `xs.split_on_p p = [xs]` -/
2533
+ lemma split_on_p_eq_single (h : ∀ x ∈ xs, ¬p x) : xs.split_on_p p = [xs] :=
2534
+ by { induction xs with hd tl ih, { refl, }, simp [h hd _, ih (λ t ht, h t (or.inr ht))], }
2535
+
2536
+ /-- When a list of the form `[...xs, sep, ...as]` is split on `p`, the first element is `xs`,
2537
+ assuming no element in `xs` satisfies `p` but `sep` does satisfy `p` -/
2538
+ lemma split_on_p_first (h : ∀ x ∈ xs, ¬p x) (sep : α) (hsep : p sep)
2539
+ (as : list α) : (xs ++ sep :: as).split_on_p p = xs :: as.split_on_p p :=
2540
+ by { induction xs with hd tl ih, { simp [hsep], }, simp [h hd _, ih (λ t ht, h t (or.inr ht))], }
2541
+
2542
+ /-- `intercalate [x]` is the left inverse of `split_on x` -/
2543
+ lemma intercalate_split_on (x : α) [decidable_eq α] : [x].intercalate (xs.split_on x) = xs :=
2544
+ begin
2545
+ simp only [intercalate, split_on],
2546
+ induction xs with hd tl ih, { simp [join], }, simp only [split_on_p_cons],
2547
+ cases h' : split_on_p (=x) tl with hd' tl', { exact (split_on_p_ne_nil _ tl h').elim, },
2548
+ rw h' at ih, split_ifs, { subst h, simp [ih, join], },
2549
+ cases tl'; simpa [join] using ih,
2550
+ end
2551
+
2552
+ /-- `split_on x` is the left inverse of `intercalate [x]`, on the domain
2553
+ consisting of each nonempty list of lists `ls` whose elements do not contain `x` -/
2554
+ lemma split_on_intercalate [decidable_eq α] (x : α) (hx : ∀ l ∈ ls, x ∉ l) (hls : ls ≠ []) :
2555
+ ([x].intercalate ls).split_on x = ls :=
2556
+ begin
2557
+ simp only [intercalate],
2558
+ induction ls with hd tl ih, { contradiction, },
2559
+ cases tl,
2560
+ { suffices : hd.split_on x = [hd], { simpa [join], },
2561
+ refine split_on_p_eq_single _ _ _, intros y hy H, rw H at hy,
2562
+ refine hx hd _ hy, simp, },
2563
+ { simp only [intersperse_cons_cons, singleton_append, join],
2564
+ specialize ih _ _, { intros l hl, apply hx l, simp at hl ⊢, tauto, }, { trivial, },
2565
+ have := split_on_p_first (=x) hd _ x rfl _,
2566
+ { simp only [split_on] at ⊢ ih, rw this , rw ih, },
2567
+ intros y hy H, rw H at hy, exact hx hd (or.inl rfl) hy, }
2568
+ end
2569
+
2570
+ end split_at_on
2571
+
2503
2572
/-! ### map for partial functions -/
2504
2573
2505
2574
/-- Partial map. If `f : Π a, p a → β` is a partial function defined on
0 commit comments