Stream: ideas

Topic: List.range shorthand syntax


view this post on Zulip Brian Teague (Feb 22 2024 at 16:54):

Anyone want shorthand syntax for List.range?

[1=..=10] == List.range { start: At 1, end: At 10 }
[0<..<8] == List.range { start: After 0, end: Before 8 }

view this post on Zulip Brendan Hansknecht (Feb 22 2024 at 17:56):

I think the syntax would need to be more complex at a minimum to deal with the automatic reverse ranges of List.range (that or we should restrict List.range which actually may be the better play).

As in, this seems wrong:

[0<..<-8] == List.range { start: After 0, end: Before -8 }

-- [-1, -2, -3, -4, -5, -6, -7] : List (Num *)

view this post on Zulip Brian Teague (Feb 22 2024 at 18:05):

Would your example need to use greater than signs instead to indicate reverse range?

[0>..>-8] == List.range { start: After 0, end: Before -8 }

view this post on Zulip Brian Teague (Feb 22 2024 at 18:08):

I think this would handle most cases
if "<" or ">", use After for start, use Before for end. If start > end, then reverse range
If "=", use At

view this post on Zulip Brendan Hansknecht (Feb 22 2024 at 18:11):

Sure, but this can't be checked statically at compile time if variables are allowed in the expression. So as a simple rewrite rule, it would be quite surprising/confusing to end users:

x = 8
[0<..<x]
-- [1, 2, 3, 4, 5, 6, 7]

x = -8
[0<..<x]
-- [-1, -2, -3, -4, -5, -6, -7]

view this post on Zulip Brendan Hansknecht (Feb 22 2024 at 18:13):

Oh actually, I think we could set the step when desugaring and it would probably be fine:

[1=..=10] == List.range { start: At 1, end: At 10, step: 1 }
-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[0<..<8] == List.range { start: After 0, end: Before 8, step: 1 }
-- [1, 2, 3, 4, 5, 6, 7]
[0<..<-8] == List.range { start: After 0, end: Before -8, step: 1 }
-- []
[0>..>-8] == List.range { start: After 0, end: Before -8, step: -1 }
-- [-1, -2, -3, -4, -5, -6, -7]

view this post on Zulip Brian Teague (Feb 22 2024 at 18:33):

Just thought of an edge case

--Should we assume step is -1 in this example because 0 is greater than -8?
[0=..=-8] -- step -1 ?

Maybe use >= and <= ?

[0=..<=-8] == List.range { start: After 0, end: Before -8, step: 1 }
-- []
[0=..>=-8] == List.range { start: After 0, end: Before -8, step: -1 }
-- [-1, -2, -3, -4, -5, -6, -7]

view this post on Zulip Brian Teague (Feb 22 2024 at 18:38):

I think it would be safe to assume the step is the same direction as the smaller vs larger value.

If it's not, then you have to use >= and <= to override this default behavior?

view this post on Zulip Brian Teague (Feb 22 2024 at 19:05):

I think this syntax would handle all scenarios:

[1=..<=10] == List.range { start: At 1, end: At 10, step: 1 }
-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[10=..<=1] == List.range { start: At 10, end: At 1, step: -1 }
-- [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[0<..<8] == List.range { start: After 0, end: Before 8, step: 1 }
-- [1, 2, 3, 4, 5, 6, 7]
[0<..<=8] == List.range { start: After 0, end: At 8, step: 1 }
-- [1, 2, 3, 4, 5, 6, 7]
[0<..<-8] == List.range { start: After 0, end: Before -8, step: 1 }
-- []
[0>..>-8] == List.range { start: After 0, end: Before -8, step: -1 }
-- [-1, -2, -3, -4, -5, -6, -7]
[0>..>=-8] == List.range { start: After 0, end: At -8, step: -1 }
-- [-1, -2, -3, -4, -5, -6, -7, -8]
[0=..>=-8] == List.range { start: At 0, end: At -8, step: -1 }
-- [0, -1, -2, -3, -4, -5, -6, -7, -8]

view this post on Zulip Anton (Feb 23 2024 at 08:56):

I like that List.range is just a normal function. @Brian Teague do you have a use case where the verbosity of List.range is bothersome?

view this post on Zulip Brian Teague (Feb 23 2024 at 17:08):

I personally use ranges a lot with Rust, and multiple languages support a similar syntax, so I wanted to ask if other people would also like it for fewer keystrokes.

Haskell uses list comprehension for step

[0, -2..=-8]
[1, 3..<10]

view this post on Zulip Agus Zubiaga (Feb 23 2024 at 17:17):

Maybe it's because I rarely use ranges, but when I do, I often have to look up the syntax. So, I like how explicit List.range currently is.

view this post on Zulip Brian Teague (Feb 23 2024 at 17:23):

That’s perfectly fine. I just wanted to see if there was any demand for the shorthand syntax as I like it and use it a lot when available. If no one else wants it, that’s perfectly okay too.

view this post on Zulip Agus Zubiaga (Feb 23 2024 at 17:27):

Sure! I'm not really opposed to it if there's demand, I'm just not part of the demand :smile:

view this post on Zulip Brendan Hansknecht (Feb 23 2024 at 20:13):

I wonder how much it would be used. In my mind, it is really common to use this type of syntax in for loops in rust. Roc doesn't have for loops and instead has tail recursion. Theoretically, one could use List.range |> List.walk to create an equivalent loop (and long term hopefully it would optimize away the intermediate list), but I almost never write that. I write the tail recursive version.

So at least from my current use of roc, I am pretty neutral. I guess I just have explicit indices in tail recursive loops most of the time. Is this a general FP difference or just a coding style...not actually sure.

view this post on Zulip Norbert Hajagos (Feb 24 2024 at 13:37):

I don't use ranges that often, so I prefer having only 1 way to it. But I think this is something that could be added to the language later on as well, if we see there is demand for it.


Last updated: Jun 16 2026 at 16:19 UTC