mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-17 18:34:06 +00:00
This PR deprecated the handful of names in core involving the component `cons₂` in favor of `cons_cons`.
509 lines
13 KiB
Lean4
509 lines
13 KiB
Lean4
set_option autoImplicit false -- For compatibility with downstream projects, so we can retest after Mathlib.
|
||
set_option relaxedAutoImplicit false
|
||
|
||
open List
|
||
|
||
variable {α : Type _}
|
||
variable {x y z : α}
|
||
variable (l l₁ l₂ l₃ : List α)
|
||
|
||
variable (L₁ L₂ : List (List α))
|
||
|
||
variable {β : Type _}
|
||
variable {f g : α → β}
|
||
|
||
variable {γ : Type _}
|
||
variable {f' : β → γ}
|
||
|
||
variable (m n : Nat)
|
||
|
||
/-! ## Preliminaries -/
|
||
|
||
/-! ### cons -/
|
||
|
||
/-! ### length -/
|
||
|
||
/-! ### L[i] and L[i]? -/
|
||
|
||
/-! ### mem -/
|
||
|
||
/-! ### set -/
|
||
|
||
/-! ### foldlM and foldrM -/
|
||
|
||
/-! ### foldl and foldr -/
|
||
|
||
/-! ### Equality -/
|
||
|
||
/-! ### Lexicographic order -/
|
||
|
||
/-! ## Getters -/
|
||
|
||
#check_simp [x, y, x, y][0] ~> x
|
||
#check_simp [x, y, x, y][1] ~> y
|
||
#check_simp [x, y, x, y][2] ~> x
|
||
#check_simp [x, y, x, y][3] ~> y
|
||
|
||
#check_simp [x, y, x, y][0]? ~> some x
|
||
#check_simp [x, y, x, y][1]? ~> some y
|
||
#check_simp [x, y, x, y][2]? ~> some x
|
||
#check_simp [x, y, x, y][3]? ~> some y
|
||
|
||
/-! ### get, get!, get?, getD -/
|
||
|
||
/-! ### getLast, getLast!, getLast?, getLastD -/
|
||
|
||
/-! ## Head and tail -/
|
||
|
||
/-! ### head, head!, head?, headD -/
|
||
|
||
#check_simp l.headD x ~> l.head?.getD x
|
||
|
||
#check_simp l.head? = none ~> l = []
|
||
|
||
/-! ### tail!, tail?, tailD -/
|
||
|
||
/-! ## Basic operations -/
|
||
|
||
/-! ### map -/
|
||
|
||
#check_simp l.map id ~> l
|
||
#check_simp l.map (fun x => x) ~> l
|
||
#check_simp [].map f ~> []
|
||
#check_simp [x].map f ~> [f x]
|
||
|
||
#check_simp map f l = map g l ~> ∀ a ∈ l, f a = g a
|
||
variable (l : List Nat) in
|
||
#check_simp map (· + 1) l = map (·.succ) l ~> True
|
||
variable (l : List Nat) in
|
||
#check_simp map (0 * ·) l ~> map (fun _ => 0) l
|
||
variable (l : List String) in
|
||
#check_simp map (fun s => s ++ s) ("a" :: l) ~> "aa" :: map (fun s => s ++ s) l
|
||
|
||
#check_simp l.map f = [] ~> l = []
|
||
|
||
variable (w : l ≠ []) in
|
||
#check_simp head (l.map f) (by simpa) ~> f (head l (by simpa))
|
||
variable (l : List String) in
|
||
#check_simp head (("a" :: l).map fun s => s ++ s) (by simp) ~> "aa"
|
||
|
||
variable (w : l ≠ []) in
|
||
#check_simp getLast (l.map f) (by simpa) ~> f (getLast l (by simpa))
|
||
|
||
#check_simp (l₁ ++ l₂).map f ~> l₁.map f ++ l₂.map f
|
||
#check_simp (l.map f).map f' ~> l.map (f' ∘ f)
|
||
#check_simp (concat l x).map f ~> map f l ++ [f x]
|
||
|
||
variable (L : List (List α)) in
|
||
#check_simp L.flatten.map f ~> (L.map (map f)).flatten
|
||
#check_simp [l₁, l₂].flatten.map f ~> map f l₁ ++ map f l₂
|
||
|
||
#check_simp l.map (Function.const α "1") ~> replicate l.length "1"
|
||
#check_simp [x, y].map (Function.const α "1") ~> ["1", "1"]
|
||
|
||
#check_simp l.reverse.map f ~> (l.map f).reverse
|
||
|
||
#check_simp (l.take 3).map f ~> (l.map f).take 3
|
||
#check_simp (l.drop 3).map f ~> (l.map f).drop 3
|
||
|
||
#check_simp l.dropLast.map f ~> (l.map f).dropLast
|
||
|
||
variable (p : β → Bool) in
|
||
#check_simp (l.map f).find? p ~> (l.find? (p ∘ f)).map f
|
||
|
||
/-! ### filter -/
|
||
|
||
/-! ### filterMap -/
|
||
|
||
/-! ### append -/
|
||
|
||
variable (w : l₁ ≠ []) in
|
||
#check_tactic head (l₁ ++ l₂) (by simp_all) ~> head l₁ w by simp_all
|
||
|
||
#check_simp (l₁ ++ l₂).head? ~> l₁.head?.or l₂.head?
|
||
#check_simp (l₁ ++ l₂).getLast? ~> l₂.getLast?.or l₁.getLast?
|
||
|
||
/-! ### concat -/
|
||
|
||
/-! ### flatten -/
|
||
|
||
#check_simp (L₁ ++ L₂).flatten ~> L₁.flatten ++ L₂.flatten
|
||
|
||
/-! ### bind -/
|
||
|
||
/-! ### replicate -/
|
||
|
||
#check_simp replicate 0 x ~> []
|
||
#check_simp replicate 1 x ~> [x]
|
||
#check_simp replicate 5 x ~> [x, x, x, x, x]
|
||
|
||
-- `∈` and `contains
|
||
|
||
#check_simp y ∈ replicate 0 x ~> False
|
||
|
||
variable [BEq α] in
|
||
#check_simp (replicate 0 x).contains y ~> false
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate 0 x).contains y ~> false
|
||
|
||
#check_simp y ∈ replicate 7 x ~> y = x
|
||
|
||
variable [BEq α] in
|
||
#check_simp (replicate 7 x).contains y ~> y == x
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate 7 x).contains y ~> y == x
|
||
|
||
-- `getElem` and `getElem?`
|
||
|
||
variable (h : n < m) (w) in
|
||
#check_tactic (replicate m x)[n]'w ~> x by simp
|
||
|
||
variable (h : n < m) in
|
||
#check_tactic (replicate m x)[n]? ~> some x by simp [h]
|
||
|
||
#check_simp (replicate 7 x)[5] ~> x
|
||
|
||
#check_simp (replicate 7 x)[5]? ~> some x
|
||
|
||
variable (w : replicate n x ≠ []) in
|
||
#check_tactic (replicate n x).head w ~> x by simp_all
|
||
|
||
variable (w : replicate n x ≠ []) in
|
||
#check_tactic (replicate n x).getLast w ~> x by simp_all
|
||
|
||
-- injectivity
|
||
|
||
#check_simp replicate 3 x = replicate 7 x ~> False
|
||
#check_simp replicate 3 x = replicate 3 y ~> x = y
|
||
#check_simp replicate 3 "1" = replicate 3 "1" ~> True
|
||
#check_simp replicate n x = replicate m y ~> n = m ∧ (n = 0 ∨ x = y)
|
||
|
||
-- append
|
||
|
||
#check_simp replicate n x ++ replicate m x ~> replicate (n + m) x
|
||
|
||
-- map
|
||
|
||
#check_simp (replicate n "x").map (fun s => s ++ s) ~> replicate n "xx"
|
||
|
||
-- filter
|
||
|
||
#check_simp (replicate n [1]).filter (fun s => s.length = 1) ~> replicate n [1]
|
||
#check_simp (replicate n [1]).filter (fun s => s.length = 2) ~> []
|
||
|
||
-- filterMap
|
||
|
||
#check_simp (replicate n [1]).filterMap (fun s => if s.length = 1 then some s else none) ~> replicate n [1]
|
||
#check_simp (replicate n [1]).filterMap (fun s => if s.length = 2 then some s else none) ~> []
|
||
|
||
-- join
|
||
|
||
#check_simp (replicate n (replicate m x)).flatten ~> replicate (n * m) x
|
||
#check_simp (replicate 1 (replicate m x)).flatten ~> replicate m x
|
||
#check_simp (replicate n (replicate 1 x)).flatten ~> replicate n x
|
||
#check_simp (replicate n (replicate 0 x)).flatten ~> []
|
||
#check_simp (replicate 0 (replicate m x)).flatten ~> []
|
||
#check_simp (replicate 0 (replicate 0 x)).flatten ~> []
|
||
|
||
-- isEmpty
|
||
|
||
#check_simp (replicate (n + 1) x).isEmpty ~> false
|
||
#check_simp (replicate 0 x).isEmpty ~> true
|
||
variable (h : ¬ n = 0) in -- It would be nice if this also worked with `h : 0 < n`
|
||
#check_tactic (replicate n x).isEmpty ~> false by simp [h]
|
||
|
||
-- reverse
|
||
|
||
#check_simp (replicate n x).reverse ~> replicate n x
|
||
|
||
-- dropLast
|
||
|
||
#check_simp (replicate 0 x).dropLast ~> []
|
||
#check_simp (replicate n x).dropLast ~> replicate (n-1) x
|
||
#check_simp (replicate (n+1) x).dropLast ~> replicate n x
|
||
|
||
-- isPrefixOf
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp isPrefixOf [x, y, x] (replicate n x) ~> decide (3 ≤ n) && y == x
|
||
|
||
attribute [local simp] isPrefixOf_cons_cons in
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp isPrefixOf [x, y, x] (replicate (n+3) x) ~> y == x
|
||
|
||
-- isSuffixOf
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp isSuffixOf [x, y, x] (replicate n x) ~> decide (3 ≤ n) && y == x
|
||
|
||
-- rotateLeft
|
||
|
||
#check_simp (replicate n x).rotateLeft m ~> replicate n x
|
||
|
||
-- rotateRight
|
||
|
||
#check_simp (replicate n x).rotateRight m ~> replicate n x
|
||
|
||
-- replace
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate (n+1) x).replace x y ~> y :: replicate n x
|
||
|
||
#check_simp (replicate n "1").replace "2" "3" ~> (replicate n "1")
|
||
|
||
-- insert
|
||
|
||
variable [BEq α] [LawfulBEq α] (h : 0 < n) in
|
||
#check_tactic (replicate n x).insert x ~> replicate n x by simp [h]
|
||
|
||
#check_simp (replicate n "1").insert "2" ~> "2" :: replicate n "1"
|
||
|
||
-- erase
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate (n+1) x).erase x ~> replicate n x
|
||
|
||
#check_simp (replicate n "1").erase "2" ~> replicate n "1"
|
||
|
||
-- find?
|
||
|
||
#check_simp (replicate (n+1) x).find? (fun _ => true) ~> some x
|
||
#check_simp (replicate (n+1) x).find? (fun _ => false) ~> none
|
||
|
||
variable {p : α → Bool} (w : p x) in
|
||
#check_tactic (replicate (n+1) x).find? p ~> some x by simp [w]
|
||
variable {p : α → Bool} (w : ¬ p x) in
|
||
#check_tactic (replicate (n+1) x).find? p ~> none by simp [w]
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? (fun _ => true) ~> some x by simp [h]
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? (fun _ => false) ~> none by simp [h]
|
||
|
||
variable {p : α → Bool} (w : p x) (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? p ~> some x by simp [w, h]
|
||
variable {p : α → Bool} (w : ¬ p x) (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? p ~> none by simp [w, h]
|
||
|
||
-- findSome?
|
||
|
||
#check_simp (replicate (n+1) x).findSome? (fun x => some x) ~> some x
|
||
#check_simp (replicate (n+1) x).findSome? (fun _ => (none : Option β)) ~> none
|
||
|
||
variable {f : α → Option β} in
|
||
#check_tactic (replicate (n+1) x).findSome? f ~> f x by simp
|
||
variable {f : α → Option β} (w : (f x).isNone) in
|
||
#check_tactic (replicate (n+1) x).findSome? f ~> none by simp_all
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? (fun x => some x) ~> some x by simp [h]
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? (fun _ => (none : Option β)) ~> none by simp [h]
|
||
|
||
variable {f : α → Option β} (w : (f x).isSome) (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? f ~> f x by simp [h]
|
||
variable {f : α → Option β} (w : (f x).isNone) (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? f ~> none by simp_all
|
||
|
||
-- lookup
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate (n+1) (x, y)).lookup x ~> some y
|
||
|
||
variable [BEq α] [LawfulBEq α] (h : 0 < n) in
|
||
#check_tactic (replicate n (x, y)).lookup x ~> some y by simp [h]
|
||
|
||
#check_simp (replicate n ("1", "2")).lookup "3" ~> none
|
||
|
||
-- zip
|
||
|
||
#check_simp (replicate n x).zip (replicate n y) ~> replicate n (x, y)
|
||
#check_simp (replicate n x).zip (replicate m y) ~> replicate (min n m) (x, y)
|
||
variable (h : n ≤ m) in
|
||
#check_tactic (replicate n x).zip (replicate m y) ~> replicate n (x, y) by simp [h, Nat.min_eq_left]
|
||
|
||
-- zipWith
|
||
section
|
||
variable (f : α → α → α)
|
||
|
||
#check_simp zipWith f (replicate n x) (replicate n y) ~> replicate n (f x y)
|
||
#check_simp zipWith f (replicate n x) (replicate m y) ~> replicate (min n m) (f x y)
|
||
variable (h : n ≤ m) in
|
||
#check_tactic zipWith f (replicate n x) (replicate m y) ~> replicate n (f x y) by simp [h, Nat.min_eq_left]
|
||
|
||
-- unzip
|
||
#check_simp unzip (replicate n (x, y)) ~> (replicate n x, replicate n y)
|
||
|
||
-- min?
|
||
|
||
-- Note this relies on the fact that we do not have `replicate_succ` as a `@[simp]` lemma
|
||
#check_simp (replicate (n+1) 7).min? ~> some 7
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n 7).min? ~> some 7 by simp [h]
|
||
|
||
-- max?
|
||
|
||
-- Note this relies on the fact that we do not have `replicate_succ` as a `@[simp]` lemma
|
||
#check_simp (replicate (n+1) 7).max? ~> some 7
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n 7).max? ~> some 7 by simp [h]
|
||
|
||
end
|
||
|
||
/-! ### reverse -/
|
||
|
||
variable (p : α → Bool) in
|
||
#check_simp (l.reverse.filter p) ~> (l.filter p).reverse
|
||
|
||
variable (f : α → Option β) in
|
||
#check_simp (l.reverse.filterMap f) ~> (l.filterMap f).reverse
|
||
|
||
#check_simp l.reverse.head? ~> l.getLast?
|
||
#check_simp l.reverse.getLast? ~> l.head?
|
||
|
||
variable (h : l.reverse ≠ []) in
|
||
#check_simp l.reverse.head h ~> l.getLast (by simp_all)
|
||
|
||
variable (h : l.reverse ≠ []) in
|
||
#check_simp l.reverse.getLast h ~> l.head (by simp_all)
|
||
|
||
/-! ## List membership -/
|
||
|
||
/-! ### elem / contains -/
|
||
|
||
/-! ## Sublists -/
|
||
|
||
/-! ### take and drop -/
|
||
|
||
/-! ### takeWhile and dropWhile -/
|
||
|
||
/-! ### partition -/
|
||
|
||
/-! ### dropLast -/
|
||
|
||
/-! ### isPrefixOf -/
|
||
|
||
/-! ### isSuffixOf -/
|
||
|
||
variable [BEq α] in
|
||
#check_simp ([] : List α).isSuffixOf l ~> true
|
||
|
||
/-! ### rotateLeft -/
|
||
|
||
/-! ### rotateRight -/
|
||
|
||
|
||
/-! ## Pairwise and Nodup -/
|
||
|
||
/-! ### Pairwise -/
|
||
section Pairwise
|
||
variable (R : α → α → Prop)
|
||
#check_simp Pairwise R [] ~> True
|
||
#check_simp Pairwise R (x :: l) ~> (∀ (a' : α), a' ∈ l → R x a') ∧ Pairwise R l
|
||
#check_simp Pairwise R [x, y, z] ~> (R x y ∧ R x z) ∧ R y z
|
||
|
||
#check_simp Pairwise R (replicate n x) ~> n ≤ 1 ∨ R x x
|
||
#check_simp Pairwise R (replicate 1 x) ~> True
|
||
#check_simp Pairwise R (replicate (n+2) x) ~> R x x
|
||
#check_simp Pairwise (· < ·) (replicate 2 m) ~> False
|
||
#check_simp Pairwise (· < ·) (replicate n m) ~> n ≤ 1
|
||
#check_simp Pairwise (· < ·) (replicate (n + 2) m) ~> False
|
||
#check_simp Pairwise (· = ·) (replicate 2 m) ~> True
|
||
#check_simp Pairwise (· = ·) (replicate n m) ~> True
|
||
|
||
end Pairwise
|
||
|
||
/-! ### Nodup -/
|
||
|
||
#check_simp Nodup [] ~> True
|
||
#check_simp Nodup (x :: l) ~> ¬x ∈ l ∧ l.Nodup
|
||
#check_simp Nodup [x, y, z] ~> (¬x = y ∧ ¬x = z) ∧ ¬y = z
|
||
|
||
#check_simp Nodup (replicate (n+2) x) ~> False
|
||
#check_simp Nodup (replicate 2 x) ~> False
|
||
|
||
/-! ## Manipulating elements -/
|
||
|
||
/-! ### replace -/
|
||
|
||
/-! ### insert -/
|
||
|
||
/-! ### erase -/
|
||
|
||
/-! ### find? -/
|
||
|
||
/-! ### findSome? -/
|
||
|
||
/-! ### lookup -/
|
||
|
||
/-! ## Logic -/
|
||
|
||
/-! ### any / all -/
|
||
|
||
/-! ## Zippers -/
|
||
|
||
/-! ### zip -/
|
||
|
||
/-! ### zipWith -/
|
||
|
||
/-! ### zipWithAll -/
|
||
|
||
/-! ## Ranges and enumeration -/
|
||
|
||
example : (List.range 1).sum = 0 := by simp
|
||
|
||
/-! ### enumFrom -/
|
||
|
||
/-! ### min? -/
|
||
|
||
/-! ### max? -/
|
||
|
||
/-! ## ofFn -/
|
||
|
||
example (f : Fin 3 → Nat) : List.ofFn f = [f 0, f 1, f 2] := rfl
|
||
|
||
-- Out of place, but lets check that `Fin.foldl` is semireducible too.
|
||
-- Well, no longer the case
|
||
-- example (f : Fin 3 → Nat) : Fin.foldl 3 (fun acc i => f i :: acc) [] = [f 2, f 1, f 0] := rfl
|
||
|
||
/-! ## Monadic operations -/
|
||
|
||
#check_simp
|
||
(Id.run do
|
||
let mut s := 0
|
||
for i in [1,2,3,4] do
|
||
s := s + i
|
||
pure s) ~> 10
|
||
|
||
#check_simp
|
||
(Id.run do
|
||
let mut s := 0
|
||
for h : i in [1,2,3,4] do
|
||
s := s + i
|
||
pure s) ~> 10
|
||
|
||
variable (l : List α) (k m : Nat) in
|
||
#check_simp
|
||
(Id.run do
|
||
let mut x := m
|
||
for _ in l do
|
||
x := x + k
|
||
pure x) ~> m + k * l.length
|
||
|
||
-- as above, but for an arbitrary monad
|
||
variable (l : List α) (k m : Nat) {M} [Monad M] [LawfulMonad M] in
|
||
#check_simp
|
||
(show M _ from do
|
||
let mut x := m
|
||
for _ in l do
|
||
x := x + k
|
||
pure x) ~> pure (m + k * l.length)
|
||
|
||
/-! ### mapM -/
|
||
|
||
/-! ### forM -/
|