前田です。

At Fri, 9 Apr 1999 09:24:01 +0900,
助田 雅紀 <masaki.suketa / systemplaza.co.jp> wrote:
> 内部イテレータを使って外部イテレータを普通は実装できないが
> 実は,Ruby ではできるという部分は私にもよくわかりません.

# 以下、内部イテレータをイテレータ、外部イテレータをカーソルと呼
# びます。

カーソルからイテレータへの変換は簡単ですよね。
例えば、nextで次の要素を返し、要素がなくなったらnilを返すカーソル
があったとすると、

class Enumerator
  def initialize(cursor)
    @cursor
  end
  
  def each
    while obj = @cursor.next
      yield(obj)
    end
  end
end

c = Cursor.new([1, 2, 3])
e = Enumerator.new(c)
e.each do |i|
  p i
end

# C++ならブロックの代りに関数ポインタや関数オブジェクトを渡すこと
# になるでしょう。

逆に、イテレータからカーソルへの変換は普通できません。
Rubyでもスマートな方法はないんじゃないかと思うのですが、スレッド
を使えばできないことはないですね。

require "thread"

class Cursor
  def initialize(iter)
    @iter = iter
    @finished = false
    @queue = Queue.new
    Thread.start do
      iter.call do |obj|
        @queue.push(obj)
      end
      @queue.push(nil) # @finished = trueだとデッドロックになりそ
                       # うな気がする
    end
  end

  def next
    if @finished
      return nil
    else
      obj = @queue.pop
      @finished = true if obj.nil?
      return obj
    end
  end
end

c = Cursor.new([1,2,3].method(:each))
while obj = c.next
  p obj
end

まつもとさんがおっしゃっているのはもっとスマートな方法なのかも...。

-- 
前田 修吾