Zulip Chat Archive

Stream: lean4

Topic: Range with steps


Floris van Doorn (Jan 26 2026 at 15:29):

What is the canonical way in Lean to write

for (i = a; i < b; i += c):
  ...

This used to be

for k in [a : b : c] do
  ...

but this is now a legacy notation.
It isn't easily written with the new Std.PRange, I believe. Is the use case where c ≠ 1 deemed obscure enough that this is not supported?

Floris van Doorn (Jan 26 2026 at 15:29):

(side remark: is it intended that for k in (2*p)...n do requires parentheses?)

Floris van Doorn (Jan 26 2026 at 15:35):

I guess I could use

for i in List.range' a ((b - a - 1) / c) c do
  ...

Sebastian Ullrich (Jan 26 2026 at 16:16):

(/cc @Paul Reichert)

Adam Topaz (Jan 26 2026 at 17:10):

#eval show IO Unit from do
  for i in [1:10:4] do
    println! i

works for me with 4.27.

Adam Topaz (Jan 26 2026 at 17:14):

There is an issue that if c is a parameter you need to prove that c > 0, and there isn't a convenient way to do this with the [a:b:c] notation, but something like this works:

def foo (a b c : Nat) : IO Unit := do
  for i in Std.Range.mk a b (c + 1) (by grind) do
    println! i

Robin Arnez (Jan 26 2026 at 17:14):

Yes, it works but if you hover over [1:10:4] it says Std.Legacy.Range

Adam Topaz (Jan 26 2026 at 17:15):

really?

Adam Topaz (Jan 26 2026 at 17:15):

what version of lean?

Robin Arnez (Jan 26 2026 at 17:16):

Latest mathlib in live lean, i.e. 4.28.0-rc1

Robin Arnez (Jan 26 2026 at 17:16):

But you're right, it's a recent change

Adam Topaz (Jan 26 2026 at 17:17):

aha ok I'm just one version behind.

Paul Reichert (Jan 26 2026 at 17:46):

You can use the stepSize combinator (which is efficient no matter what the step size is):

import Std

def f (n : Nat) : IO Unit := do
  for x in (1...n).iter.stepSize 2 do
    IO.println (toString x)

#eval f 10

This is admittedly less convenient than the previous notation. Step sizes aren't integrated more deeply into the ranges to keep the complexity in check, given that there are some complications with the polymorphism of the new ranges.

Floris van Doorn (Jan 26 2026 at 18:10):

Adam Topaz said:

There is an issue that if c is a parameter you need to prove that c > 0, and there isn't a convenient way to do this with the [a:b:c] notation, but something like this works:

def foo (a b c : Nat) : IO Unit := do
  for i in Std.Range.mk a b (c + 1) (by grind) do
    println! i

I was indeed also running into this issue.

Floris van Doorn (Jan 26 2026 at 18:12):

Paul Reichert said:

You can use the stepSize combinator (which is efficient no matter what the step size is):

Oh, this is nice! docs#Std.IterM.stepSize is indeed what I was looking for. The notation is indeed less nice, but still pretty good.


Last updated: Feb 28 2026 at 14:05 UTC