Skip to content

Commit 05b64be

Browse files
kim-emluisacicolini
authored andcommitted
chore: deprecate List.iota (leanprover#6708)
This PR deprecates `List.iota`, which we make no essential use of. `iota n` can be replaced with `(range' 1 n).reverse`. The verification lemmas for `range'` already have better coverage than those for `iota`. Any downstream projects using it (I am not aware of any) are encouraged to adopt it.
1 parent eb89adf commit 05b64be

File tree

11 files changed

+127
-58
lines changed

11 files changed

+127
-58
lines changed

src/Init/Data/List/Basic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,11 +1520,14 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat
15201520
`O(n)`. `iota n` is the numbers from `1` to `n` inclusive, in decreasing order.
15211521
* `iota 5 = [5, 4, 3, 2, 1]`
15221522
-/
1523+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
15231524
def iota : Nat → List Nat
15241525
| 0 => []
15251526
| m@(n+1) => m :: iota n
15261527

1528+
set_option linter.deprecated false in
15271529
@[simp] theorem iota_zero : iota 0 = [] := rfl
1530+
set_option linter.deprecated false in
15281531
@[simp] theorem iota_succ : iota (i+1) = (i+1) :: iota i := rfl
15291532

15301533
/-! ### enumFrom -/
@@ -1848,12 +1851,14 @@ def unzipTR (l : List (α × β)) : List α × List β :=
18481851
/-! ### iota -/
18491852

18501853
/-- Tail-recursive version of `List.iota`. -/
1854+
@[deprecated "Use `List.range' 1 n` instead of `iota n`." (since := "2025-01-20")]
18511855
def iotaTR (n : Nat) : List Nat :=
18521856
let rec go : Nat → List Nat → List Nat
18531857
| 0, r => r.reverse
18541858
| m@(n+1), r => go n (m::r)
18551859
go n []
18561860

1861+
set_option linter.deprecated false in
18571862
@[csimp]
18581863
theorem iota_eq_iotaTR : @iota = @iotaTR :=
18591864
have aux (n : Nat) (r : List Nat) : iotaTR.go n r = r.reverse ++ iota n := by

src/Init/Data/List/Nat/Range.lean

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -195,24 +195,32 @@ theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n -
195195

196196
/-! ### iota -/
197197

198+
section
199+
set_option linter.deprecated false
200+
201+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
198202
theorem iota_eq_reverse_range' : ∀ n : Nat, iota n = reverse (range' 1 n)
199203
| 0 => rfl
200204
| n + 1 => by simp [iota, range'_concat, iota_eq_reverse_range' n, reverse_append, Nat.add_comm]
201205

202-
@[simp] theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range']
206+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
207+
theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range']
203208

204-
@[simp] theorem iota_eq_nil {n : Nat} : iota n = [] ↔ n = 0 := by
209+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
210+
theorem iota_eq_nil {n : Nat} : iota n = [] ↔ n = 0 := by
205211
cases n <;> simp
206212

213+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
207214
theorem iota_ne_nil {n : Nat} : iota n ≠ [] ↔ n ≠ 0 := by
208215
cases n <;> simp
209216

210-
@[simp]
217+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
211218
theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 0 < m ∧ m ≤ n := by
212219
simp [iota_eq_reverse_range', Nat.add_comm, Nat.lt_succ]
213220
omega
214221

215-
@[simp] theorem iota_inj : iota n = iota n' ↔ n = n' := by
222+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
223+
theorem iota_inj : iota n = iota n' ↔ n = n' := by
216224
constructor
217225
· intro h
218226
have h' := congrArg List.length h
@@ -221,6 +229,7 @@ theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 0 < m ∧ m ≤ n := by
221229
· rintro rfl
222230
simp
223231

232+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
224233
theorem iota_eq_cons_iff : iota n = a :: xs ↔ n = a ∧ 0 < n ∧ xs = iota (n - 1) := by
225234
simp [iota_eq_reverse_range']
226235
simp [range'_eq_append_iff, reverse_eq_iff]
@@ -234,6 +243,7 @@ theorem iota_eq_cons_iff : iota n = a :: xs ↔ n = a ∧ 0 < n ∧ xs = iota (n
234243
rw [eq_comm, range'_eq_singleton]
235244
omega
236245

246+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
237247
theorem iota_eq_append_iff : iota n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = (range' (k + 1) (n - k)).reverse ∧ ys = iota k := by
238248
simp only [iota_eq_reverse_range']
239249
rw [reverse_eq_append_iff]
@@ -245,42 +255,52 @@ theorem iota_eq_append_iff : iota n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = (rang
245255
· rintro ⟨k, h, rfl, rfl⟩
246256
exact ⟨k, by simp; omega⟩
247257

258+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
248259
theorem pairwise_gt_iota (n : Nat) : Pairwise (· > ·) (iota n) := by
249260
simpa only [iota_eq_reverse_range', pairwise_reverse] using pairwise_lt_range' 1 n
250261

262+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
251263
theorem nodup_iota (n : Nat) : Nodup (iota n) :=
252264
(pairwise_gt_iota n).imp Nat.ne_of_gt
253265

254-
@[simp] theorem head?_iota (n : Nat) : (iota n).head? = if n = 0 then none else some n := by
266+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
267+
theorem head?_iota (n : Nat) : (iota n).head? = if n = 0 then none else some n := by
255268
cases n <;> simp
256269

257-
@[simp] theorem head_iota (n : Nat) (h) : (iota n).head h = n := by
270+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
271+
theorem head_iota (n : Nat) (h) : (iota n).head h = n := by
258272
cases n with
259273
| zero => simp at h
260274
| succ n => simp
261275

262-
@[simp] theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
276+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
277+
theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
263278
cases n <;> simp
264279

265-
@[simp] theorem reverse_iota : reverse (iota n) = range' 1 n := by
280+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
281+
theorem reverse_iota : reverse (iota n) = range' 1 n := by
266282
induction n with
267283
| zero => simp
268284
| succ n ih =>
269285
rw [iota_succ, reverse_cons, ih, range'_1_concat, Nat.add_comm]
270286

271-
@[simp] theorem getLast?_iota (n : Nat) : (iota n).getLast? = if n = 0 then none else some 1 := by
287+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
288+
theorem getLast?_iota (n : Nat) : (iota n).getLast? = if n = 0 then none else some 1 := by
272289
rw [getLast?_eq_head?_reverse]
273290
simp [head?_range']
274291

275-
@[simp] theorem getLast_iota (n : Nat) (h) : (iota n).getLast h = 1 := by
292+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
293+
theorem getLast_iota (n : Nat) (h) : (iota n).getLast h = 1 := by
276294
rw [getLast_eq_head_reverse]
277295
simp
278296

297+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
279298
theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
280299
(iota n).find? p = none ↔ ∀ i, 0 < i → i ≤ n → !p i := by
281300
simp
282301

283-
@[simp] theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
302+
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
303+
theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
284304
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
285305
rw [find?_eq_some_iff_append]
286306
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
@@ -317,6 +337,8 @@ theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
317337
· omega
318338
· omega
319339

340+
end
341+
320342
/-! ### enumFrom -/
321343

322344
@[simp]

src/Lean/Language/Basic.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ language server.
185185
-/
186186
def withAlwaysResolvedPromises [Monad m] [MonadLiftT BaseIO m] [MonadFinally m] [Inhabited α]
187187
(count : Nat) (act : Array (IO.Promise α) → m Unit) : m Unit := do
188-
let ps ← List.iota count |>.toArray.mapM fun _ => IO.Promise.new
188+
let ps ← Array.range count |>.mapM fun _ => IO.Promise.new
189189
try
190190
act ps
191191
finally

tests/bench/mergeSort/Bench.lean

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ def main (args : List String) : IO Unit := do
55
let some arg := args[0]? | throw <| IO.userError s!"specify length of test data in multiples of 10^{k}"
66
let some i := arg.toNat? | throw <| IO.userError s!"specify length of test data in multiples of 10^{k}"
77
let n := i * (10^k)
8-
let i₁ := List.iota n
8+
let i₁ := (List.range' 1 n).reverse
99
let i₂ := List.range n
1010
let i₃ ← (List.range n).mapM (fun _ => IO.rand 0 1000)
11-
let i₄ := (List.range (i * (10^(k-3)))).bind (fun k => (k * 1000 + 1) :: (k * 1000) :: List.range' (k * 1000 + 2) 998)
11+
let i₄ := (List.range (i * (10^(k-3)))).flatMap (fun k => (k * 1000 + 1) :: (k * 1000) :: List.range' (k * 1000 + 2) 998)
1212
let start ← IO.monoMsNow
13-
let o₁ := (mergeSortTR₂ (· ≤ ·) i₁).length == n
14-
let o₂ := (mergeSortTR₂ (· ≤ ·) i₂).length == n
15-
let o₃ := (mergeSortTR₂ (· ≤ ·) i₃).length == n
16-
let o₄ := (mergeSortTR₂ (· ≤ ·) i₄).length == n
13+
let o₁ := (mergeSortTR₂ i₁).length == n
14+
let o₂ := (mergeSortTR₂ i₂).length == n
15+
let o₃ := (mergeSortTR₂ i₃).length == n
16+
let o₄ := (mergeSortTR₂ i₄).length == n
1717
IO.println (((← IO.monoMsNow) - start)/4)
1818
IO.Process.exit (if o₁ && o₂ && o₃ && o₄ then 0 else 1)

tests/lean/derivingHashable.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ structure Foo where
66
flag : Bool
77
deriving Hashable
88

9-
#eval hash <| { name := "Joe", val := List.iota 40, flag := true, inv := by decide : Foo }
9+
#eval hash <| { name := "Joe", val := (List.range' 1 40).reverse, flag := true, inv := by decide : Foo }
1010

1111
inductive Tree (α : Type) where
1212
| node : List (Tree α) → Bool → Tree α
1313
| leaf : α → Tree α
1414
deriving Hashable
1515

16-
#eval hash <| Tree.node (List.iota 10 |>.map fun i => Tree.node [Tree.leaf i] (i%2==0)) true
16+
#eval hash <| Tree.node ((List.range' 1 10).reverse |>.map fun i => Tree.node [Tree.leaf i] (i%2==0)) true
1717

1818
inductive StructureLikeInductive where
1919
| field : Nat -> StructureLikeInductive

tests/lean/run/IO_test.lean

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ withFile fn2 Mode.append $ fun h => do
6262
{ h.putStrLn xs₁;
6363
pure () };
6464
let ys ← withFile fn2 Mode.read $ fun h => do
65-
{ let ys ← (List.iota 4).mapM $ fun i => do
65+
{ let ys ← (List.range 4).mapM $ fun i => do
6666
{ let ln ← h.getLine;
6767
IO.println i;
6868
IO.println ∘ repr $ ln;
@@ -80,13 +80,13 @@ info: ⟨[₂,α]⟩⟨[₂,α]⟩
8080
8181
[₂,α]⟩⟨[₂,α]
8282
83-
4
83+
0
8484
"⟨[₂,α]⟩⟨[₂,α]⟩\n"
85-
3
85+
1
8686
"/* Handle.getLine : Handle → IO Unit *//* The line returned by `lean_io_prim_handle_get_line` *//* is truncated at the first '\\0' character and the *//* rest of the line is discarded. */\n"
8787
2
8888
"⟨[6,8,@]⟩\n"
89-
1
89+
3
9090
"⟨[6,8,@]⟩\n"
9191
[⟨[₂,α]⟩⟨[₂,α]
9292
, /* Handle.getLine : Handle → IO Unit *//* The line returned by `lean_io_prim_handle_get_line` *//* is truncated at the first '\0' character and the *//* rest of the line is discarded. */

tests/lean/run/derivingRepr.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ info: { name := "Joe",
1515
flag := true }
1616
-/
1717
#guard_msgs in
18-
#eval { name := "Joe", val := List.iota 40, flag := true, inv := by decide : Foo }
18+
#eval { name := "Joe", val := (List.range' 1 40).reverse, flag := true, inv := by decide : Foo }
1919

2020
inductive Tree (α : Type) where
2121
| node : List (Tree α) → Bool → Tree α
@@ -37,7 +37,7 @@ info: Tree.node
3737
true
3838
-/
3939
#guard_msgs in
40-
#eval Tree.node (List.iota 10 |>.map fun i => Tree.node [Tree.leaf i] (i%2==0)) true
40+
#eval Tree.node ((List.range' 1 10).reverse |>.map fun i => Tree.node [Tree.leaf i] (i%2==0)) true
4141

4242
inductive StructureLikeInductive where
4343
| field : Nat -> StructureLikeInductive

tests/lean/run/filter.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
#guard ((List.iota 1000000).filter (fun x => x % 2 = 1)).length = 500000
1+
#guard ((List.range 1000000).filter (fun x => x % 2 = 1)).length = 500000

tests/lean/run/forInPArray.lean

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,31 +45,73 @@ IO.println s!"sum: {sum}"
4545
return sum
4646

4747
/--
48-
info: x: 100
49-
x: 98
50-
x: 96
51-
x: 94
52-
x: 92
53-
x: 90
54-
x: 88
55-
x: 86
56-
x: 84
57-
x: 82
58-
x: 80
59-
x: 78
60-
x: 100
61-
x: 98
62-
x: 96
63-
x: 94
64-
x: 92
65-
x: 90
66-
x: 88
67-
x: 86
68-
x: 84
69-
x: 82
70-
x: 80
71-
x: 78
72-
sum: 1068
48+
info: x: 0
49+
x: 2
50+
x: 4
51+
x: 6
52+
x: 8
53+
x: 10
54+
x: 12
55+
x: 14
56+
x: 16
57+
x: 18
58+
x: 20
59+
x: 22
60+
x: 24
61+
x: 26
62+
x: 28
63+
x: 30
64+
x: 32
65+
x: 34
66+
x: 36
67+
x: 38
68+
x: 40
69+
x: 42
70+
x: 44
71+
x: 46
72+
x: 48
73+
x: 50
74+
x: 52
75+
x: 54
76+
x: 56
77+
x: 58
78+
x: 60
79+
x: 62
80+
x: 64
81+
x: 0
82+
x: 2
83+
x: 4
84+
x: 6
85+
x: 8
86+
x: 10
87+
x: 12
88+
x: 14
89+
x: 16
90+
x: 18
91+
x: 20
92+
x: 22
93+
x: 24
94+
x: 26
95+
x: 28
96+
x: 30
97+
x: 32
98+
x: 34
99+
x: 36
100+
x: 38
101+
x: 40
102+
x: 42
103+
x: 44
104+
x: 46
105+
x: 48
106+
x: 50
107+
x: 52
108+
x: 54
109+
x: 56
110+
x: 58
111+
x: 60
112+
x: 62
113+
x: 64
114+
sum: 1056
73115
-/
74116
#guard_msgs in
75-
#eval check (f1 (List.iota 100).toPArray' 1000) (f2 (List.iota 100).toPArray' 1000)
117+
#eval check (f1 (List.range 100).toPArray' 1000) (f2 (List.range 100).toPArray' 1000)

tests/lean/run/parray1.lean

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ def check [BEq α] (as : List α) : Bool :=
66
def tst1 : IO Unit := do
77
assert! check [1, 2, 3]
88
assert! check ([] : List Nat)
9-
assert! check (List.iota 17)
10-
assert! check (List.iota 533)
11-
assert! check (List.iota 1000)
12-
assert! check (List.iota 2600)
9+
assert! check (List.range 17)
10+
assert! check (List.range 533)
11+
assert! check (List.range 1000)
12+
assert! check (List.range 2600)
1313
IO.println "done"
1414

1515
/-- info: done -/

tests/lean/run/task_test2.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ n.repeat (fun r =>
88

99
def tst (n : Nat) : IO UInt32 :=
1010
let ys := (List.replicate n 1);
11-
let ts : List (Task Nat) := (List.iota 10).map (fun i => Task.spawn fun _ => run1 (i+1) n ys);
11+
let ts : List (Task Nat) := (List.range 10).map (fun i => Task.spawn fun _ => run1 (i+1) n ys);
1212
let ns : List Nat := ts.map Task.get;
1313
IO.println (">> " ++ toString ns) *>
1414
pure 0

0 commit comments

Comments
 (0)