Ross Bamford
2/16/2006 11:23:00 AM
Hi,
Well, I've snapped a string on my guitar and my computer won't play MP3s
today for some reason, so inevitably boredom started to creep in. I
started playing around with the generator stuff, specifically about the
coroutine discussion earlier in this thread. Just wanted to see if I
could *really* get my head around continuations and all that.
It starts with some private methods on Kernel, which are then used to
implement the generator, but can be used elsewhere too:
module Kernel
private
def coreset(blk)
Thread.current[:"#{blk.inspect.hash}_codone"] = nil
end
def coyield?(blk)
Thread.current[:"#{blk.inspect.hash}_codone"] ? false : true
end
def coyield(blk, *args)
raise "Coroutine exhausted" if Thread.current[:"#{blk.inspect.hash}_codone"]
catch :coreturn do
next_item = (Thread.current[:coreturn] ||= []).pop
if next_item
next_item.call
else
final = blk.call(*args)
Thread.current[:"#{blk.inspect.hash}_codone"] = true
throw :coreturn, final
end
end
end
def coreturn(val)
callcc do |return_cc|
(Thread.current[:coreturn] ||= []) << return_cc
throw :coreturn, val
end
end
end
class CoGenerator
def initialize(enum = nil, &blk)
@blk, @pos = blk, 0
if enum
@blk = lambda { enum.each { |e| coreturn e } }
end
end
def rewind
@pos = 0
coreset @blk
end
def next
@pos += 1
@current = coyield(@blk)
end
def current
@current
end
def next?
coyield? @blk
end
def end?
!self.next?
end
def each
rewind
yield coyield(@blk) while coyield?(@blk)
end
def pos
@pos
end
end
It would be used like:
g = CoGenerator.new do
coreturn 6
# Some work
coreturn 7
# More work
coreturn 8
# Yet more work
9
end
p g.next while g.next?
# ->
# 6
# 7
# 8
# 9
Obviously this isn't for the quiz (it'd be dead last, being based on
continuations, and it doesn't actually have the Generator API) but just,
well, for fun. And something to do. It was fun to write, but it's a toy.
I dread to think what it mightn't do properly, or at all :) It's
behaviour in multithreaded code could well be a bit counter-intuitive
too, I'm afraid I don't know much about how coroutines work in other
languages.
It times a bit faster than the old callcc generator, because it's using
less continuations (just the one) but really I guess it's just a test of
the coyield/coreturn stuff.
Anyway, enough about that... Music shop will be open now :)
--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk