On Thu, 10 May 2018 15:02:39 -0000 Michael Jones <michael.jo...@gmail.com> 
wrote:
> 
> Maybe the central issue here has been lost because of the confusion between
> English words and the keywords of various languages. Let's be explicit: *a
> controlled looping construct may test the control condition before or after
> the iterated body of code. Go's 'for' tests before and and Go does not
> provide keyword means to specify the test happen after.*
> 
> Not a crisis, everyone works around this, but, the workaround is a
> workaround. Language shapes thought. Languages that express test-after in
> their vocabulary embrace code and data structuring that depend on it.
> People who know such languages (such as C and others) will miss it. In 800
> AD Charlemagne said, "To have a second language is to have a second soul."
> Same for computer languages.
Rather than add simple syntatic sugar like "while" or "until",
it would make more sense to add a more powrrful & generalized
loop syntax.

Motivating example:
If you want to iterate through two slices at the same rate,
the "for" syntax doesn't generalize well. You have to do

for i, v := range slice1 {
    if i >= len(slice2) { break; }
    u := slice2[i]
    ....
}

This loses the similarity in the way v & u take successive
values from slice1 and slice2. Basically Go's for takes the
first step from "for i := 0; i < N; i++ { ... }" but then
stops.

A generalized loop can clearly bring out the similarity:

Example1:
loop for v := range slice1
     for u := range slice2 {
     ...
}

This iterates through both slices and exits when either range
is exhausted.

It can be more powerful by adding filtering, value generation
and exit tests as loop phrases.

Example2:
loop for v := range slice
     while v != 10 {
        ...
}

This ends as soon as v becomes 10.

Example3:
loop for v := range slice
     until v != 10 {
        ...
}

Here the "until" test is done at the end of the loop (so the
body will be executed with v == 10 *once* but not for any
further values from slice).

Example4:
loop for x := range slice 
     for y := 2*iota+1  // y takes values 1, 3, 5, ...
        ...
}

Here an expression around Go's wonderful "iota" is used to
generate successive values.  The loop ends once the slice
range is exhausted.

Example5:
loop for x := 2*iota+1  // x takes values 1, 3, 5, ...
     if IsPrime(x)
     while x < 100 {
        ...
}

Here the loop body is executed for only prime valued x and terminates
when x becomes > 100.

"range slice" in effect is a generator. In a sense so is
"iota". If we allow use of a generator function in a loop
phrase, things get more interesting.

Example6:
// primegen returns a prime generator function
func primegen() func() int {
        p := 2
        return func() int {
                for {
                        q := p
                        if p == 2 { p += 1} else { p += 2 }
                        if IsPrime(q) { return q }
                }
        }
}

prime := primegen()
loop for x := prime()
     for y := iota
     while y < 100 {
        fmt.Println(x)
}

Here primegen() returns a new function that returns successive
primes every time it is called. The loop prints out first 100
primes.

This generalized loop should translate in a straightforward
way to go1 style "for" loop code.

Credit: Common Lisp's LOOP macro.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to