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 }
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 *)
Would your example need to use greater than signs instead to indicate reverse range?
[0>..>-8] == List.range { start: After 0, end: Before -8 }
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
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]
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]
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]
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?
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]
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?
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]
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.
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.
Sure! I'm not really opposed to it if there's demand, I'm just not part of the demand :smile:
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.
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