内部イテレータと外部イテレータ

ときどき聞く言葉ですが、違いを知らなかったのでちょっと調べてみました。GoFデザインパターン聖典(^^;に記述がありました。
それによると、イテレータの内部でぐるぐる回すのが内部イテレータ。対して、イテレータを使ってイテレータの外で回すのが外部イテレータ
まあ、まんまなんですが、例を挙げると List の ForEach( Action action ) とか ConvertAll( Converter converter ) なんかが内部イテレータ。一般的によく使われる、foreach ( T item in list ) { ... } みたいな使い方が外部イテレータ
LINQ to Object の Select や Where なんかは内部イテレータですね。←LINQ to Object をこう説明すれば通じる人には一瞬で通じるのかもしれません。

「内部イテレータは簡単に使える。外部イテレータは内部イテレータより柔軟」とのこと。そうですねぇ。
以前、List の FindAll と ConvertAll を組み合わせて使おうとして困ったことがあります。FindAll に複数の条件を与えて、「条件A」に一致した場合は「変換A」、「条件B」に一致した場合は「変換B」を使うみたいなことができないんですよね。2回に分ければいいんですが、そうすると両方の条件に一致する要素を後で捨てる処理が必要になったりして、それも馬鹿馬鹿しい感じ。この問題は LINQ にもありますね。パズル的にやってできないことはないけど実用的じゃない、みたいな。で、解決策としては何でも屋の ForEach が必要でしょうってことで。ForEach がないのは、LINQ to Object には簡単に作れても、ほかの LINQ に用意できないからなのかなぁ。

「また、内部イテレータは無名関数やクロージャや継続を提供していない言語には不向きである。」とも記述があります。今となってはそうですねって感想ですが、ちょっと前の自分だったらこの文の意味が理解できなかっただろうなぁ。というか、この本、昔読んだときはあんまり理解できなかったけど、今読むとスラスラ読めるなぁ。Smalltalk はわからないままだけど。

k.inabaさんのところで (http://www.kmonos.net/wlog/41.php の 04/08/09) yield が内部イテレータ風に外部イテレータを書ける構文って記述を見つけました。なるほど、そう考えるとスッキリ説明できますね!プチ感動。

関連 id:NyaRuRu:20070818 とかあちこち