Io Language で yielding

とある言語で generator が入るらしいというのをみてしまった。
generator + yielding の仕組みらしい。なにそれ python。
(内部イテレータや外部イテレータについてはここでは触れない感じです。)

Generator + yield

ジェネレータは、僕の認識だと closure のような仕組みに yielding できるインタフェースを用意したものだと思ってる
それゆえ yielding で使う構文である yield さんを単体で使うというよりセットで使っているものが多そう

例えば、こんな感じのループとか

1
2
3
4
5
6
7
8
9
10
##### python
def gen():
  for i in range(10):
    print i
    yield

hoge = gen()
hoge.next() # => 0
hoge.next() # => 1
hoge.next() # => 2

なので、 yield 単体でも動きそうで動かない

1
2
3
4
5
6
7
8
9
def yielding():
  i = 0;
  while(1):
    i = i + 1
    print i
    yield

yielding()
yielding()

io での yield

IoLanguage における yield は、単なるコンテキストスイッチ(というか、キューイングされた次の処理の実行(シングルスレッドで実行されるtimerのような))に近い感じがしている

先ほど書いた python のコードは、io だと全然違う動きをする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
yielding := block(
  for(i, 0, 3,
    i println
    yield
  )
)

yielding call()

// =>[results]
0
1
2
3

全然 yield してないです..
あくまで一つの処理を終えてから、次の処理に行こうとしてそうです。(yieldで止まらない)

ということで、呼び出し自体を非同期にする @ とか @@ を使います

1
2
3
4
5
6
7
8
9
10
11
12
13
14
yielding := block(
  for(i, 0, 3,
    i println
    yield
  )
)

yielding @@call
yield // async call を元処理に戻す
yield // 次の yield を呼び出す

// => [results]
0
1

loop でも使える

1
2
3
4
5
6
7
8
9
10
11
12
count := block(
  counter := 0
  loop(
    counter = counter + 1
    counter println
    yield
  )
)
count @call
yield // => 1
yield // => 2
yield // => 3

yield とひとくくりにしても、処理系によって意味合いが違うのがいいですね。
(Java とかの Thread#yield があったけど、大まか iolang のような意味合いだったよーな)

io でも Generator (actor)

さて、ここまで出来たのですが、 python の generator のように、外部イテレータ側に値を返したいです
そんなとき便利な actor

1
2
3
4
5
6
7
8
9
10
11
12
13
generator := method(
  counter := 0
  block(
    counter = counter + 1
  )
)

foo := generator
val_1 := foo @call
val_2 := foo @call

val_1 println // => 1
val_2 println // => 2

とりあえず、これで動きそう。もはや yield どこ行ったって感じだけど。
promise でもできそうです。

1
2
3
4
5
6
7
8
9
10
11
12
13
generator2 := method(next,
  counter := 0
  block (
    counter = counter + 1
    next(counter)
  )
)

foo := generator2(method(v, v println))
foo @@call
yield
foo @@call
yield

ここで yield 使ってるので、 @@ で呼び出したコルーチンを呼び戻すため
ということで、ここまで