Luke Graham
3/11/2005 1:45:00 PM
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 <spoooq@gmail.com> wrote:
> On Fri, 11 Mar 2005 15:57:08 +0900, Roshan James <roshanj@microsoft.com> 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