gop
gop copied to clipboard
Support range function in Python
In Python, the range function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default), and stops before a specified number.
For example:
>>> x = range(10)
>>> print(x)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
In machine learning, we often training a model with a number of epochs. If we want to train a model with 10 epochs, we write codes like this:
for epoch in range(10):
# do training
# do evaluation at the end of an epoch
print("epoch %d: evaluation metrics", epoch)
In Go, we have to write codes like this:
for epoch := 0; epoch < 10; epoch++ {
}
for epoch in range(10) is shorter than for epoch := 0; epoch < 10; epoch++.
I am working on gotorch project, and I try to write a deep learning model example with different frontend languages https://github.com/wangkuiyi/gotorch/issues/23. Here is the training loop part.
Could we do something in Go+? Thank you!
my proposal is as follows
[[start]...stop,[step]]
ie.
println([1...6,2])
prints new array [1,3,5]
println([...5])
prints new array [0,1,2,3,4]
println([...5,2])
prints new array [0,2,4]
There are two ways to reach the goal.
- Treat
rangeas a builtin function.
func range(n int) []int {
...
}
- Treat
rangeas an iterator that looks like a lazy initialized slice:
for x <- range(1e8) { // allow N be a huge number
...
}
range should have three input paramters : start number(optional,default 0,included),step number(optional,default 1) and stop number(required,excluded)
@xushiwei Good suggestions.
Actually, there are two built-in functions in Python2, range and xrange. range returns a sequence of numbers, while xrange returns an iterable object.
In Python3, there is no xrange, and range returns an iterable object.
So, I prefer the second way. It's consistent with Python3.
As @JessonChan commented, there are three input parameters of range.
// case 1
for x <- range(0, 1, 10) {
}
// case 2
for x <- range(10) {
}
// case 3
for x <- range(1, 2, 10) {
}
The case 2 is equal to case 1. However, Go does not support optional parameters.
Any suggestions from Go+? Thank you!
However, Go does not support optional parameters.
Any suggestions from Go+? Thank you!
This is not a problem. If range is a function. it can be:
func range(start int, options ...int) []int {
var step, stop int
switch len(options) {
case 0:
start, step, stop = 0, 1, start
case 1:
step, stop = 1, options[0]
case 2:
step, stop = options[0], options[1]
default:
painc("...")
}
...
}
I would like to propose the rust/haskell syntax [1..10] (note the two dots, this is convenient because it is distinct from the three dots used for variadic functions). Haskell allows you to do steps as well: [5,10..100]. I feel like this is much more elegant than a builtin function, on top of being more concise. Also, range is already a keyword in go, and it's the one used for iterating over a list. so your code would actually look like for i := range range(10), which is not very clear at all.
I would like to propose the rust/haskell syntax
[1..10](note the two dots, this is convenient because it is distinct from the three dots used for variadic functions). Haskell allows you to do steps as well:[5,10..100]. I feel like this is much more elegant than a builtin function, on top of being more concise. Also, range is already a keyword in go, and it's the one used for iterating over a list. so your code would actually look likefor i := range range(10), which is not very clear at all.
It looks cool. And I think [5,10..100] is ambiguous to [5,10,100] until parsing the .. token. I think maybe [10..100:5] is better.
- range(N):
[..N]or[0..N] - range(M, N):
[M..N] - range(M, step, N):
[M..N:step]
I really don't like having the step on the end. Haskell doesn't actually have you specify a step, I has you specify a list that you want continued. This means [7, 9..20] resolves to [7,9,11,13,15,17,19]. I don't get your statement on ambiguity, every statement is ambiguous to an infinite number of statements until the last token is parsed, why would this be any different? I will admit however that the [10..100:5] syntax is my second favorite, although I would much prefer mine.
[...] is not only for variadic functions but also specifying a length equal to the number of elements in the literal of an array (array := [...]string{"a", "b", "c"}). So I prefer to use ... not .. as the notation.
In List-comprehension, we use , to separate body and condition , so , is better than : in this range funciton.
[...] is not only for variadic functions but also specifying a length equal to the number of elements in the literal of an array (array := [...]string{"a", "b", "c"}). So I prefer to use ... not .. as the notation. In List-comprehension, we use , to separate body and condition , so , is better than : in this range funciton.
To me, both of these facts suggest the opposite, as both of those operators already have uses, and shouldn't have even more uses added on. Related to this is the problem go is having with () vs [] for generics. The reason people don't want () is because it makes things confusing to read, as you end up with things like Foo(int,string)(i,str).
I also think that borrowing a notation from another language is a better choice for superficial things like this, otherwise people will have to remember extra syntax for no reason.
In every example you listed, It doesn't do what I expect. I especially don't like the stop argument being exclusive. [...5] resolving to [0,1,2,3,4] just seems wrong. To me, .. (or ...) represents elements being omitted from a list, so [1...6,2] represents a list that starts with 1 and ends with 6 followed by 2, which doesn't make sense. This is why I like Haskell's syntax of [1, 3..6]. It's also why I don't hate [1..6:2] as the : makes it clear that the :2 is it's own thing, not an element in the list.
There's also the basic argument that ..is less typing than ..., which is generally a good thing.
They ended up going with https://github.com/goplus/gop/blob/main/doc/docs.md#range-for
for i <- :5 {
println i
// 0
// 1
// 2
// 3
// 4
}
for i <- 1:5 {
println i
// 1
// 2
// 3
// 4
}
for i <- 1:5:2 {
println i
// 1
// 3
}