Generator/Exponential: Difference between revisions

Content added Content deleted
(→‎{{header|Go}}: added channel version)
Line 687: Line 687:
fmt.Print(fGen(), " ")
fmt.Print(fGen(), " ")
}
}
fmt.Println("")
fmt.Println()
}</lang>
}</lang>
Output:
Output:
Line 693: Line 693:
529 576 625 676 784 841 900 961 1024 1089
529 576 625 676 784 841 900 961 1024 1089
</pre>
</pre>
Alternatively, generators can be implemented in Go with goroutines and channels. There are tradeoffs however, and often one technique is a significantly better choice.

Goroutines can run concurrently, but there is overhead associated with thread scheduling and channel communication. Flow control is also different. A generator implemented as a closure is a function with a single entry point fixed at the beginning. On repeated calls, execution always starts over at the beginning and ends when a value is returned. A generator implemented as a goroutine, on the other hand, "returns" a value by sending it on a channel, and then the goroutine continues execution from that point. This allows more flexibility in structuring code.
<lang go>package main

import (
"fmt"
"math"
)

func newPowGen(e float64) chan float64 {
ch := make(chan float64)
go func() {
for i := 0.; ; i++ {
ch <- math.Pow(i, e)
}
}()
return ch
}

// given two input channels, a and b, both known to return monotonically
// increasing values, supply on channel c values of a not returned by b.
func newMonoIncA_NotMonoIncB_Gen(a, b chan float64) chan float64 {
ch := make(chan float64)
go func() {
for va, vb := <-a, <-b; ; {
switch {
case va < vb:
ch <- va
fallthrough
case va == vb:
va = <-a
default:
vb = <-b

}
}
}()
return ch
}

func main() {
ch := newMonoIncA_NotMonoIncB_Gen(newPowGen(2), newPowGen(3))
for i := 0; i < 20; i++ {
<-ch
}
for i := 0; i < 10; i++ {
fmt.Print(<-ch, " ")
}
fmt.Println()
}</lang>


=={{header|Haskell}}==
=={{header|Haskell}}==