Callcc problem in Generator

G

Greg Fitzgerald

Hey all,

I was playing with the Generator class the other day and decided I
didn't like that you can't break out while iterating through the
generator without first having already taken the time to iterate to
the element after the one you were at when you decided to break out.

The following code shows what I mean. It runs through
test_generator() twice, the first with the current implementation of
Generator, and the second with a new one I whipped up. It shows that
the current implementation takes longer to execute when breaking out
early. Also, outside of performance, I don't like that if I were
reading a stream of data and decided to break out, it would read one
too many lines--kind of an ugly side-effect.

Unfortunately, there's a significant bug in my version that I been
trying to crack all night and I can't figure it out for the life of
me. I want to be able to start iterating, then midway through, call
rewind(), and then start iterating through again. When I do that, it
leaves the stack in an odd place, and when I call each(), it will make
it all the way to the end then get caught in an infinite loop inside
next?().

So I guess my question is, if you create a continuation with callcc()
and then decide never to call that continuation, is there some way to
unwind the stack?

Thanks,
Greg



require 'generator'

def test_generator()
timeStart = Time.now
puts "start constructing at #{Time.now - timeStart}"
gen = Generator.new do |g|
for num in [1,2,3,4,5]
sleep(3)
g.yield(num)
end
end

puts "finished constructing at #{Time.now - timeStart}"

puts "getting first element at #{Time.now - timeStart}"
for num in gen
puts num
break if num == 3
puts "getting next element at #{Time.now - timeStart}"
end
puts "done at #{Time.now - timeStart}"

puts "\n\n"
end

puts "Ruby's Generator"
test_generator()

class EndOfGenerator < Exception
end

class Generator
def initialize(&closure)
@closure = closure
return rewind()
end

def each()
rewind()

while self.next?()
yield self.next()
end
return self
end

def rewind()
@closureEntryPoint = nil
@currentElement = nil
@nextElement = nil
@position = -1
#self.next?()
return self
end

def pos()
return @position
end

def current()
if @currentElement == nil
begin
self.next()
@nextElement = @currentElement
rescue EndOfGenerator
end
end

return @currentElement
end

def next?()
return true if @nextElement
begin
@nextElement = self.next()
return true
rescue EndOfGenerator
return false
end
end

def end?()
return !self.next?()
end

def next()
if @nextElement
@currentElement = @nextElement
else
@currentElement = callcc do |cc|
@generatorEntryPoint = cc
if @closureEntryPoint == nil
@closure.call(self)
raise EndOfGenerator.new()
else
@closureEntryPoint.call()
end
end
@position += 1
end
@nextElement = nil
return @currentElement
end

def yield(obj)
return callcc do |cc|
@closureEntryPoint = cc
@generatorEntryPoint.call(obj)
end
end
end

puts "Corrected generator"
test_generator()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top