I'm getting close to wrapping up the new PickAxe. One of the last things I need is an example of symetric coroutines for the standard library section on the Fiber class.
I have lots of asymetric examples, but I'm struggling to come up with something decent for symetric coroutines (which use transfer to pass control between themselves.) I've coded up Conway's line squeezer, but it works better using asymetric coroutines. I've tried to come up with puzzles that are best solved with symetric coroutines, but without luck. I've coded up a simple blackjack game, but again it works better with asymetric coroutines. Although, for fun, here's the dealer, which shows some of the new Ruby 1.9 array methods:
But, I'm still stuck. So... can any of you clever folk come up with something compelling that uses less that 35 lines of code?
I have lots of asymetric examples, but I'm struggling to come up with something decent for symetric coroutines (which use transfer to pass control between themselves.) I've coded up Conway's line squeezer, but it works better using asymetric coroutines. I've tried to come up with puzzles that are best solved with symetric coroutines, but without luck. I've coded up a simple blackjack game, but again it works better with asymetric coroutines. Although, for fun, here's the dealer, which shows some of the new Ruby 1.9 array methods:
But, I'm still stuck. So... can any of you clever folk come up with something compelling that uses less that 35 lines of code?




the dining philosophers problem ?
I'm not sure i understand, but if by symmetric you mean full coroutines (which yield and resume) a fairly good example is a state machine. The problem is finding a case where you need to stop the computation to wait for the next input.
In that case, IRB (or other REPLs) represents a good example: you have a state machine to parse ruby statements, move to a new state, yield a new prompt and wait for the next token to decide what sub-action to take next.
But I'm probably misunderstanding :)
Posted by: gabriele renzi | January 20, 2009 at 08:22 PM
Dining philosophers is really about resource management: I looked at it, and it doesn't really work. State machines are good, but I struggled to find something that fits into the constraints of a half page and which also makes sense.
Posted by: Dave Thomas | January 20, 2009 at 08:31 PM
What about the prisoners dilemma? You could implement the tit for tat strategy or any other.
Posted by: erik | January 20, 2009 at 08:53 PM
@gabriele: I think you have them backwards: a *symmetric* coroutine is a coroutine which has *one* function to yield control to another coroutine. An *asymmetric* coroutine is a coroutine which has *two* functions, one for *suspending* the coroutine and another for *resuming* another suspended coroutine.
Asymmetric coroutines are also sometimes called *semi-coroutines*, because their asymmetry means they aren't really "co". However, that is an unfortunate name, because semi-coroutine also has a different meaning: it means a coroutine which can only suspend when its call stack is empty, i.e. it can only suspend from within its body but not from within another function. This kind of crippled coroutine is also sometimes called a *generator* (Python, C#, JavaScript).
Posted by: Jörg W Mittag | January 20, 2009 at 10:19 PM
For the state machine idea: what about implementing a simple regular expression? Something like this: https://Gist.GitHub.Com/49866/ ?
Posted by: Jörg W Mittag | January 20, 2009 at 11:50 PM
Just a quick head's up. The code samples from Gist don't appear in Google Reader. Other than that, excited for the new Pick Axe!
Posted by: Seth Ladd | January 21, 2009 at 03:06 AM
Same fringe problem? I solved it once using continuations to emulate coroutines, so it should be easy to convert to a fiber example.
See http://onestepback.org/articles/same_fringe/index.html
Posted by: Jim Weirich | January 21, 2009 at 07:04 AM
I'm seeing the same thing as Seth (no gist in Google Reader). Also, could someone point out where the 1.9-specific array portion is? All that code seems like it works under 1.8.5 to me. Thanks
Posted by: Ben Orenstein | January 21, 2009 at 08:08 AM
@ben:
Arrays don't have product and shuffle in pre-1.9 ruby, unless you're using something like facets.
Posted by: pete | January 21, 2009 at 04:21 PM
Dave,
I did not even know that Ruby had symmetric coroutines.
Maybe it would be helpful if you shared some of your code for better understanding of the problem?
Cheers
Robert
Posted by: Robert Dober | January 27, 2009 at 05:48 AM
Token passing seems like a great example. Quick hackery led me to this example:
http://pastie.org/372299
It's not a great example, I don't know what to write to educate people, that's your area. :)
I couldn't think of meaningful work for the machines to do but it would be interesting in encryption or image processing I think. Each machine with it's own encryption key doing a set amount of cycles before passing on to the next machine.
Posted by: Chuck Vose | January 27, 2009 at 12:07 PM
Ah I seem to see, symmetric coroutines in Ruby are just using a subset of the API, transferring control amongst themselves. This is a new concept to me. (obviously Lua influence bite me)
I somehow cannot stop of thinking about continuations, setting up fibers to transfer to other fibers. Could we do something like Scheme's amb?
I keep thinking about this, but wanted to share the idea because I am sure there are brighter people than me here ( not many of course ;).
Posted by: Robert Dober | January 28, 2009 at 09:03 AM