From: dolio@... (Dan Doel) Date: 2003-07-23T11:40:28+09:00 Subject: Re: callcc and insomnia > Dan, it seems that by calling the "call" method you do two things: > 1) push more input values into the coroutine and > 2) get the next return value. > Is this what you wanted to achieve? Wouldn't it be better to separate > those two things? > > Just interested, > Pit I guess it depends on how you prefer things. If you look here: http://www.sidhe.org/~dan/blog/archives/000178.html which is the place that I took my coroutine syntax/semantics from, it has a discussion of all the ways you can pass arguments to a coroutine. For those that don't care to read the whole article, there's 3 ways: 1) When the coroutine's first called, you take those arguments and use them until the coroutine finishes and take new arguments at the next start 2) Start the coroutine over when called with a new set of arguments 3) Replace arguments with the new arguments but don't restart at the beginning. My code actually only does number 1. If you look, the first time in, it calls the function with the arguments, and then until the function falls off the end, it just jumps back in where it left off, without changing the arguments. It wouldn't be hard to implement 2 (store the args in something like @args and compare before deciding whether to jump or call), and, to my knowledge, 3 can't be done unless you require that people do something like: def foo(x, y, z) ... x, y, z = yield val1 ... x, y, z = yield val2 ... end cot = Coroutine.new method(:foo) ... In which case the person who defines the corouting gets to choose between 1 and 3 (although I think 3 is generally not seen to be good). To that end you could make routines that expect a different number of arguments each time they are called, which would be a little weird and I can't think of any time you'd use it, but you could do it! Unfortunately, I don't think there's any 'elegant' way of letting people choose 2 while still allowing 1 and 3, although 3 facilitates a user implementation of 2: def foo(x, y, z) cc2 = nil x, y, z = callcc { |cc| cc2 = cc ; x, y, z } ... a, b, c = yield val1 cc2.call(a, b, c) unless (x == a) && (y == b) && (z == c) ... end (Might not work exactly as I think, since I just wrote that up on the spot and haven't tested it) That's kind of ugly code, though. Anyway, I think I've forgotten to answer your question. The code does what I intended. :) If you wanted a Perl 6 coroutine (as I understand them), you could do something like this (don't yell at me for global variables :), you can use class or instance variables at your leisure): $cot = nil def coroutine_impl(xx, yy, zz) ... end def coroutine(x, y, z) if($cot == nil) $cot = Coroutine.new method(:coroutine_impl) end $cot.call(x, y, z) end And then you just call coroutine x, y, z to your hearts content and it looks like a transparent function call just like a Perl 6 coroutine. Not that this has a whole lot of benefit for the work involved, but I did it more to help myself understand callcc than to actually have something useful. I've since thought about the Scheme implementation of such a beast, but I still can't wrap my head around it exactly. Then again, it's different than the Ruby implementation because you need to pass in a return function which isn't exactly usual in scheme (there isn't exactly a 'yeild' that does what it does in Ruby). Hope this clears some stuff up, and sorry again for the long post.