From: Luke Graham Date: 2005-03-11T23:13:54+09:00 Subject: Re: Is iterating in lock-step possible? More or less compliant with the generator.rb api, which I like. Some proof that the thing works, too. module Enumerable attr_accessor :co, :st, :res, :sto def nextco each_with_index { |e,i| callcc { |cc| @co = cc @res = e @st.call } } @res = nil @st.call end def next (t = @sto; @sto = nil; return t) if @sto callcc { |cc| @st = cc @co ? @co.call : nextco } return @res end def next? @sto = self.next if !@sto @sto end end a = [1,2,4] b = [3,5,'lots'] puts a.next b.next? b.next? b.next? while a.next? and b.next? puts a.next,b.next end On Fri, 11 Mar 2005 23:58:30 +1000, Luke Graham wrote: > Just found this, it seems to fit the bill nicely and its in the std > lib of all places :P > > http://www.ruby-doc.org/stdlib/libdoc/generator/rdoc/classes/Generator.html > > On Fri, 11 Mar 2005 23:44:39 +1000, Luke Graham wrote: > > Gah, always miss something when I post code... > > > > Replace the first two lines of nextco with > > def nextco > > each_with_index { |e,i| > > > > > > On Fri, 11 Mar 2005 23:41:46 +1000, Luke Graham wrote: > > > On Fri, 11 Mar 2005 15:57:08 +0900, Roshan James wrote: > > > > > > > I was trying to write code where I can have two or more computations > > > > which generate values that I need to compare - with the ruby syntax > > > > tying iterator usage to the code blocks by syntax, there is no way I can > > > > do this. This is especially applicable when the iterators potentially > > > > return an infinite stream of values. (Except for using contiuations... > > > > Which is not really so much of a solution, because I might as well not > > > > have used an iterator in a first place if I could create good > > > > coroutines) > > > > > > Continuations are the right answer in this case. > > > > > > module Enumerable > > > attr_accessor :co, :st, :res > > > > > > def nextco > > > each { |e| > > > callcc { |cc| > > > @co = cc > > > @res = e > > > @st.call > > > } > > > } > > > @res = nil > > > @st.call > > > end > > > def next > > > callcc { |cc| > > > @st = cc > > > @co ? @co.call : nextco > > > } > > > return @res > > > end > > > end > > > > > > a = [1,2,3] > > > b = [4,5,6,7,8] > > > > > > while x = a.next and y = b.next > > > puts x,y > > > end > > > > > > Note there are three possible behaviours around the @res = nil > > > line. One is to return nil after all items have been used up, another > > > is to keep returning the last item by removing that line, and finally > > > a loop can be wrapped around the each, to begin returning from > > > the first item again. > > > > > > Its probably possible to do it in one function, but it makes more > > > sense to me in two. > > > > > > > Yes I understand that I take a hit (wrt perf by choosing ruby), but > > > > that's a BAD argument to favour wrapping state first by a iterators and > > > > then once over by a continuation. > > > > > > As long as its wrapped safely and nicely, what does it matter? > > > This way, you even get your choice of what to do when you > > > run out of items ;) > > > > > > -- > > > spooq > > > > > > > -- > > spooq > > > > -- > spooq > -- spooq