エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

関数プログラミングと無限論理多項式(24)

Go の例(4) (ゴルーチン)

クロージャーを使っている部分をゴルーチンで置き換えたものを考えます。

イテレーターをゴルーチンで実装した IteratorChannelImpl_int 構造体と IteratorChannelIOImpl_Numbers 構造体を作成します。

type IteratorChannelImpl_int struct {
	ch            chan int
	current_digit int
}

func newIteratorChannelImpl_int(ch chan int) *IteratorChannelImpl_int {
	xyz := new(IteratorChannelImpl_int)
	xyz.ch = ch
	xyz.current_digit = 0
	return xyz
}
func (xyz *IteratorChannelImpl_int) GetCurrent() int {
	return xyz.current_digit
}
func (xyz *IteratorChannelImpl_int) MoveNext() bool {
	val, ok := <-xyz.ch
	xyz.current_digit = val
	return ok
}
func (xyz *IteratorChannelImpl_int) Take(count int) []int {
	res := make([]int, count)
	iter := xyz
	for i := 0; i < count && iter.MoveNext(); i++ {
		res[i] = iter.GetCurrent()
	}
	return res
}
type IteratorChannelIOImpl_Numbers struct {
	ch_get          chan *Numbers
	ch_set          chan *Numbers
	current_numbers *Numbers
}

func newIteratorChannelIOImpl_Numbers(ch_get chan *Numbers, ch_set chan *Numbers) *IteratorChannelIOImpl_Numbers {
	xyz := new(IteratorChannelIOImpl_Numbers)
	xyz.ch_get = ch_get
	xyz.ch_set = ch_set
	xyz.current_numbers = <-xyz.ch_get
	return xyz
}
func (xyz *IteratorChannelIOImpl_Numbers) GetCurrent() *Numbers {
	return xyz.current_numbers
}
func (xyz *IteratorChannelIOImpl_Numbers) SetCurrent(value *Numbers) {
	xyz.ch_set <- value
}
func (xyz *IteratorChannelIOImpl_Numbers) MoveNext() bool {
	val, ok := <-xyz.ch_get
	xyz.current_numbers = val
	return ok
}
func (xyz *IteratorChannelIOImpl_Numbers) Take(count int) []*Numbers {
	res := make([]*Numbers, count)
	iter := xyz
	for i := 0; i < count && iter.MoveNext(); i++ {
		res[i] = iter.GetCurrent()
	}
	return res
}

NumbersGenerator 構造体とそのメソッドは以下のように IteratorChannelImpl_int 構造体で実装します。

type NumbersGenerator struct {
	generator *IteratorChannelImpl_int
}

func newNumbersGenerator() *NumbersGenerator {
	xyz := new(NumbersGenerator)
	xyz.generator = xyz.GenerateDecimal()
	return xyz
}
func (xyz *NumbersGenerator) GetNextDecimalDigit() int {
	xyz.generator.MoveNext()
	return xyz.generator.GetCurrent()
}

func (xyz *NumbersGenerator) GenerateDecimal() *IteratorChannelImpl_int {
	ch := make(chan int)
	serv := func(ch chan int) {
		number := newLongDecimal([]int{})
		square_difference := newLongDecimal([]int{3})
		nums := newNumbers(number, square_difference, 0)
		for {
			ch <- nums.GetNextDecimalDigit()
		}
	}
	go serv(ch)
	return newIteratorChannelImpl_int(ch)
}

NumbersServer 構造体とそのメソッドは以下のように IteratorChannelIOImpl_Numbers 構造体で実装します。

type NumbersServer struct {
	current_numbers  *Numbers
	generator_server *IteratorChannelIOImpl_Numbers
}

func newNumbersServer() *NumbersServer {
	xyz := new(NumbersServer)
	xyz.current_numbers = newNumbers(newLongDecimal([]int{}), newLongDecimal([]int{}), 0)
	xyz.generator_server = xyz.GenerateDecimalServer()
	return xyz
}
func (xyz *NumbersServer) GetNumbers() *Numbers {
	return xyz.generator_server.GetCurrent()
}
func (xyz *NumbersServer) SetNumbers(numbers *Numbers) {
	xyz.generator_server.SetCurrent(numbers)
}
func (xyz *NumbersServer) GenerateDecimalServer() *IteratorChannelIOImpl_Numbers {
	ch_get := make(chan *Numbers)
	ch_set := make(chan *Numbers)
	serv := func(ch_get chan *Numbers, ch_set chan *Numbers) {
		number := newLongDecimal([]int{})
		square_difference := newLongDecimal([]int{3})
		nums := newNumbers(number, square_difference, 0)
		for {
			ch_get <- nums
			nums = <-ch_set
		}
	}
	go serv(ch_get, ch_set)
	return newIteratorChannelIOImpl_Numbers(ch_get, ch_set)
}

Iterate 関数を使っている部分について、今までの例では実行順序が固定だったので問題なかったのですが、ゴルーチンを使ったこの例では実行順序が不定となるようです。間違っていたところを修正することにします。この修正は今までの例でもやった方が良いです。

Numbers 構造体をコピーするメソッドを作成します。

func (xyz *Numbers) Copy() *Numbers {
	return newNumbers(xyz.number, xyz.square_difference, xyz.scale)
}

NextNumbers 関数を構造体をコピーするように修正します。

func NextNumbers(numbers *Numbers) *Numbers {
	new_numbers := numbers.Copy()
	new_numbers.GetNextDecimalDigit()
	return new_numbers
}