ささだです。

Yusuke ENDOH さんは書きました:
> 一般的な意味にあわせるのが一番いいと思います。
> 
> 不勉強ながら私は fiber や coroutine 関連の論文や他言語の仕様を
> 読んだことがないので、その答えはわかりません。すみません。



> 私が [ruby-dev:30924] の挙動に違和感を覚えた理由は Fiber の意味を
> callcc の単純なラッパとして理解していて、それと同じ挙動を期待したからです。
> つまり、[ruby-dev:30924] は以下とほぼ等価かと。
> 
> f = proc do |prev|
>  p 1
>  prev.call
>  p 2
> end
> 
> f2 = proc do |prev|
>  callcc {|current| f.call(current) }
> end
> 
> callcc {|current| f2.call(current) }
> 
> # 脳内変換規則
> #  Fiber.new    ==>  proc {|prev| ... }
> #  Fiber#yield  ==>  callcc {|current| self.call(current) }
> 
> 
> しかしこの変換規則だと Fiber を導入する意味がほとんどなさそうなので
> こちらの方が一般的に採用されているとか、便利な例が多そうだということなら、
> 私の違和感は無視してください。

 ほかの言語の例は実は試していないんですが、win32api の Fiber
は SEGV しました。これはあんまりだ。

 確認しているのは lua と modula-2 なんですが、それぞれ Fiber
(Coroutine)の終了時にはどうなるのか教えてくれる人はいないで
すかね。lua なら試せるかな。

 とりあえず、いくつかアプリケーションを作ってみてから考えたほ
うがいいような気がしています。


> あ、あと、呼び出しを Fiber.new { ... }.yield でくくるだけで挙動が変わる
> 関数が定義できてしまうことに抵抗があったというのもあります。
> そういう黒魔術は callcc だけでいい、みたいな。
> 
> def foo
>    Fiber.new do
>        p 1
>        Fiber.prev.yield
>        p 2
>    end.yield
> end
> 
> # Fiber.new do
>    # 何かいろいろやる
>    foo
>    # 何かいろいろやる
>    # Fiber.new でくくっていると忘れた頃に p 2 が実行される
> # end.yield

 表現力の高い coroutine を実現するための仕組みなので、(わか
らないと)不思議なことがあるのはそういうものかなぁ、と思いま
す。また、ほかの例でも同じような現象が起こります。たとえば、
Thread#pass(Thread#critical)では同じようなことが起こります
が、これは黒魔術でしょうか。

 ただし、過剰な自由度は混乱させるだけな気もしています。なの
で、たとえば python のような制限付き coroutine のようにして提
供するのも一案かと思っています。

 ちなみに、python では generator が終了したら例外を返します。
これはこれで納得できる話です。

-- 
// SASADA Koichi at atdot dot net