From: William Morgan Date: 2005-02-12T04:42:07+09:00 Subject: Re: continuations and throw / catch Excerpts from William Morgan's mail of 11 Feb 2005 (EST): > Here's something I whipped up that lets you suspend and resume an > arbitrary function. For simplicity, it doesn't pass return values from > resume/suspend, but it wouldn't be too hard to modify it to do that. What the hey, here's a version that lets you pass values with suspend and resume as well. It's not too much more complex. class Resumable def initialize(&proc) @inside = nil @outside = nil @proc = proc end def callable?; @inside.nil?; end def resumable?; !@inside.nil?; end alias :done? :callable? def call(*a) raise "not in callable state" unless callable? callcc do |c| @outside = c ret = @proc.call(self, *a) @inside = nil @outside.call(ret) end end def resume(*a) raise "not in a resumable state" unless resumable? callcc do |c| @outside = c @inside.call(*a) end end def suspend(*a) raise "not in a suspendable state" unless @outside callcc do |c| @inside = c @outside.call(*a) end end end ## example f = Resumable.new do |r, *args| puts "a: started (args #{args.join(', ')})" y = r.suspend "hello" puts "a: said hello, got #{y}" y = r.suspend "how\'s it going?" puts "a: said how's it going, got #{y}" y = r.suspend "goodbye!" puts "a: done! said goodbye, got #{y}" "see ya!" end puts "calling" x = f.call "howdy" puts "initial call: got #{x}" i = 0 until f.done? m = "message #{i}" puts "b: resuming with #{m}" x = f.resume m puts "b: got #{x}" i += 1 end puts "done!" ## end Output is: calling a: started (args howdy) initial call: got hello b: resuming with message 0 a: said hello, got message 0 b: got how's it going? b: resuming with message 1 a: said how's it going, got message 1 b: got goodbye! b: resuming with message 2 a: done! said goodbye, got message 2 b: got see ya! done! -- William