Yuh-Ruey Chen wrote: > Yes, this is exactly what I'm looking for - the ability to chain > iterators like this without creating intermediate arrays, hopefully > using less memory. I've researched this a bit more, and it seems that ruby 1.9 *does* support this model in a very smart way. Unfortunately the built-in Enumerable methods like #map, #select, #reject don't, but these are easy enough to synthesise. I started a new thread on that topic at http://www.ruby-forum.com/topic/169807 Anyway, if you want the following pattern generator --> filter --> filter ... --> consumer you implement it as follows. (1) The generator is any object which implements 'each' and yields the members of the (possibly infinite) collection. class Fib include Enumerable def initialize(a=1,b=1) @a, @b = a, b end def each a, b = @a, @b yield a while true yield b a, b = b, a+b end end end (by including Enumerable, you gain a whole load of useful methods which in turn call your 'each' method) (2) The consumer is an object which calls 'each' with a block that does something with the data yielded to it: obj.each { |i| puts i } So far, all so ruby-1.8. (3) The clever bit is the filter, and this only works in ruby-1.9. You create an Enumerator object with a block which processes the data. Enumerator.new do |y| obj.each do |thing| # the filter INPUT ... y << otherthing # the filter OUTPUT end end The really clever bit is the "y << otherthing" line. By cunning use of Fibers (I believe), execution of the filter stops at this point, allowing the next filter along the chain to make use of the value as its input. Once all the filters along the chain have finished using this value, this filter carries on into the next iteration of its 'each' loop, to take the next input from upstream. So here's a complete example with an infinite source, two filters, and a consumer. Notice that only the consumer decides when to terminate; before this point, everything is a potentially infinite series. module Enumerable def lmap(&blk) Enumerator.new do |y| each do |e| y << blk[e] end end end def lselect(&blk) Enumerator.new do |y| each do |e| y << e if blk[e] end end end end class Fib include Enumerable def initialize(a=1,b=1) @a, @b = a, b end def each a, b = @a, @b yield a while true yield b a, b = b, a+b end end end Fib.new.lselect { |i| i % 2 == 0 }.lmap { |i| "<#{i}>" }. each_with_index { |i,cnt| puts i; break if cnt >= 20 } $ ruby19 fib.rb <2> <8> <34> <144> <610> <2584> <10946> <46368> <196418> <832040> <3524578> <14930352> <63245986> <267914296> <1134903170> <4807526976> <20365011074> <86267571272> <365435296162> <1548008755920> <6557470319842> -- Posted via http://www.ruby-forum.com/.