Scalaの限定継続とかC#のyieldに関するお話

6
kmizu @kmizu

@ufcpp 今更感があるのですけど、少し指摘を。2.7ベースとのことですが、TraversableOnceやgroupByは2.8以降に入ったものですし、Iteratorのソースも2.8のものです。ですから、バージョンについては勘違いされているのではないかと。 #scala

2011-07-24 18:27:45
kmizu @kmizu

@ufcpp それで、2.8ベースである以上、限定継続はやはりあるので、脚注辺りででも補足いただけると嬉しいです。なんか注文つけてすいませんが、記事自体はよいものだと思います。

2011-07-24 18:28:50
kmizu @kmizu

@ufcpp ちなみに、Javaはスレッドがあるので、普通にジェネレータかけます(実用性はともかく)。id:lethevert さんのブログに http://t.co/6bfbF0Z 実装そのものが載っています。

2011-07-24 18:31:00
ると @cocoa_ruto

ある言語でPythonのジェネレータ的なものが書けるかどうか問題にしてるときにスレッドがあるからOKというのは有りなのか。確かに無しかと言われるとジェネレターの定義がはっきりしない以上無しではないと言わざるを得ないだろうけど。

2011-07-24 18:52:11
ると @cocoa_ruto

今のJavaならSynchronousQueue使うのが正解だろうか > ジェネレータ的なものの実装

2011-07-24 18:54:10
kmizu @kmizu

Iterator.scalaのmap実装の、2.7.7.final と 2.8.0.final での違い。 http://bit.ly/oLRvEi @ITの記事が2.7ベース http://bit.ly/oTv0W0 というのはやはり勘違いかと。

2011-07-24 19:03:47
++C++; // 管理人: 岩永 @ufcpp

@kmizu groupBy自体、教えていただいて後から追記したものではあります。いやー、提出後、すでにこと切れてしまっており、限定継続について調べる気力がなく… パッと見た感じ、RubyのEnumeratorに近い(Fiber的なものを使って内部列挙から外部列挙生成)ですか?

2011-07-24 20:41:35
++C++; // 管理人: 岩永 @ufcpp

@kmizu スレッドを使ってのジェネレーターはいくらなんでも効率が悪すぎますね。コンテキストスイッチの負荷は相当高いので。JRubyのFiberはそういう方式で効率が悪いと効きますが。あとまあ、「実装者視点でも楽」という要件も課しているいるので、単に「書ける」はいまいちです。

2011-07-24 20:43:17
kmizu @kmizu

@ufcpp なるほど。そうでしたか。お疲れさまです。機能的には、C# のyield まんま + RubyのEnumerator的なこともできると言った感じです。限定継続自体が汎用的な機能で、その上で、ジェネレータもできるし、Fiber的なものもできるし…というのが実態です。

2011-07-24 20:45:57
kmizu @kmizu

@ufcpp はい。スレッドによる実装は効率が悪い、というのは承知の上で書きました。あとは、Javaだと継続使えるライブラリがいくつかあるので、そういうのを使えば効率の良いジェネレータはそこそこ楽に実装できます。

2011-07-24 20:47:38
++C++; // 管理人: 岩永 @ufcpp

@kmizu あれ、文法に手を入れずにできましたっけ?<C# のyield的な。どこか参考になるページはあります?

2011-07-24 20:49:45
++C++; // 管理人: 岩永 @ufcpp

@kmizu その継続は、どんな感じですか?関数型言語で結構使う継続呼び出しだと、個人的に、制御フロー的な書き方と、継続的な書き方だと、前者の方が書きたい意図にまだ近く、後者は「しょうがないから人間が頑張る」だと思っています。

2011-07-24 20:52:00
kmizu @kmizu

@ufcpp はい。できます。参考としては、Scala実践プログラミングをご購入いただければ…というのは冗談ですが、英語圏だとたとえば http://bit.ly/nWLNSv のページとかにGeneratorの実装が載っていますね。 #scalajp

2011-07-24 20:56:08
kmizu @kmizu

@ufcpp ちょっとややこしいですが、Scala 2.8で入った限定継続というのは継続の変種みたいなもので、発祥は関数型言語です。で、継続をそのまま使うと色々と面倒ですが、

2011-07-24 20:57:45
kmizu @kmizu

@ufcpp 制御フロー的な書き方からジェネレータを作るライブラリは簡単に書ける、といったところです。

2011-07-24 20:58:20
kmizu @kmizu

@ufcpp あと、自分でもいくつかジェネレータライブラリを自作したことがあります。大昔のだと、 http://bit.ly/pBw7Fn とか。 #scalajp

2011-07-24 21:00:05
++C++; // 管理人: 岩永 @ufcpp

@kmizu たぶん、yielder(x) みたいに書いたところで一度処理を止める必要があるはずですけども、それはどうやります?C# みたいにコンパイラーが頑張る、Pythonみたいにsetjmp/longjmp、あるいは、スレッドを使って一度Waitのどれかになると思いますが

2011-07-24 21:02:18
kmizu @kmizu

@ufcpp 他にも、StackOverFlowで http://bit.ly/mQoN7a な実装があったりと、自家製ジェネレータの実装があちこちに氾濫してる感じです。

2011-07-24 21:04:05
kmizu @kmizu

@ufcpp はい。それは限定継続自体がやってくれる(実行状態を保存してくれる)ので、プログラマは何もする必要がありません。

2011-07-24 21:04:45
++C++; // 管理人: 岩永 @ufcpp

@kmizu そのページのGeneratorの中でblockingEnqueueしてますが、これがどうブロックしてるかって部分ですね。タスクプール(Javaの場合、Futureでしたっけ?)ですかねぇ?

2011-07-24 21:06:39
kmizu @kmizu

@ufcpp ちょっと表現がうまくなかったので訂正です。限定継続自体がコンパイラに対する拡張として実装されていて、その意味で言えば、コンパイラが頑張っているといえなくもないです。ただ、「yieldのために」特別にコンパイラが頑張ることはない、といったところでしょうか。

2011-07-24 21:07:32
++C++; // 管理人: 岩永 @ufcpp

@kmizu うーん、内部実装どうなっているんだろう…C# の場合、ドキュメントにあるんですよね、yield returnの展開結果が。Scalaの限定継続はどうなってるのか、どこかにドキュメントはありますか?

2011-07-24 21:10:55
kmizu @kmizu

@ufcpp あるにはあるんですが、実は展開結果の公式ドキュメントが論文 http://bit.ly/rhE2Se くらいしか無いという…。おおざっぱな解説をすると、局所的にCPS変換という変換処理をコンパイラが行って、継続を取り出せる形式に変換しています。 #scalajp

2011-07-24 21:14:14
++C++; // 管理人: 岩永 @ufcpp

@kmizu うーん…どうしよう… 個人的に、「ドキュメントが論文しかない」だと記事に取り入れる気にはなれず(「公式にサポートされてる」レベルとして認定しかねる)… 制御フロー的なものを継続に変換だと、F# のコンピューテーション式が近いですかねぇ?

2011-07-24 21:20:48
kmizu @kmizu

@ufcpp はい。blockingEnqueueしてる部分が、それに該当します。ただ、普通のGeneratorより汎用的な実装を意図してるっぽいので、例としてはあまりうまくなかったです。先ほど貼ったStackOverFlowの例とか、自分の例とかがそこそこシンプルでしょうか。

2011-07-24 21:21:47
1 ・・ 5 次へ