From: Rudolf Polzer Date: 2003-04-03T07:53:21+09:00 Subject: Generators again I didn't understand the Generators using callcc() example I read some time ago, so I tried it on my own. Maybe my class is more understandable to others, too... Somehow my approach reminded me of good old DOS times (cooperative multitasking implemented in Turbo Pascal)... and in fact, cooperative multitasking could be implemented by round-robin calling generators. The usage of that 'no' variable might remind of C a bit... (I just say setjmp/longjmp), although this thing doesn't seem possible with C: The stack context will be invalidated if the function which called setjmp() returns. (and that's exactly what those TP hacks did: they used a seperate stack segment for every cooperative "thread") I think this is the main difference between continuations and setjmp/longjmp. class Generator def initialize(&block) pr = lambda() do |r| r[0] block[r] end no = 0 callcc() do |cont| @cont = cont end no += 1 if no == 1 then pr[lambda() do |v| @retval = v get_out_of_here() end] lastcont = @cont @cont = nil lastcont.call() end end def next!() raise "read beyond end of generator" if @cont == nil get_out_of_here() return nil if @cont == nil return @retval end def get_out_of_here() no = 0 lastcont = @cont callcc() do |cont| @cont = cont end no += 1 if no == 1 then lastcont.call() end end private :get_out_of_here end # that's a generator using another one def summation(gen) Generator.new() do |send| sum = 0 while v = gen.next!() sum += v send[sum] end end end # a sample generator fib = Generator.new() do |send| a, b = 0, 1 while true a, b = b, a+b send[a] end end fibsum = summation(fib) while true p fibsum.next!() end