Hi all, I'm more-or-less thinking out loud for a bit here. I'd appreciate any thoughts or comments people might want to make.
So, I have the CPS module: http://search.cpan.org/~pevans/CPS-0.04/lib/CPS.pm On its own it doesn't create an awful lot of real interest yet; nothing much that can't easily be done with "normal perl". But this wasn't yet the point. I'm thinking of ways to combine it nicely with IO::Async (or other event frameworks, but I'll take this as a useful example). My primary thought is how to combine things like kwhile() with other events; ideally it'd be nice to interleave kwhile() loops with other event processing. ((I pick on kwhile here specifically, because all the other k*() control-flow structures are built on kwhile(), so getting that right gives the others for free)). Imagine the normal while loop with some event handling: while( cond ) { do_something(); process_pending_events(); } What if instead we had an IO::Async-aware version of CPS. Lets say, for the sake of argument, we had some sort of object, which knows of the IO::Async loop.. lets call it, for reasons that'll become clear soon, a Governor: my $governor = CPS::Governor::IOAsync->new( $loop ); $governor->kwhile( sub { my ( $knext, $kdone ) = @_; return $kdone->() if !cond; do_something( on_done => $knext ); }, sub { say "Finished" } ); Aside from the slightly messy syntax, this is a fairly short and convenient way to mix CPS with IO::Async. The Governor object can mix iterations of the while loop with other event processing in a neat simple way. In fact, given as it can store state, we can configure it more powerfully than just this. Suppose we're processing a big list of, maybe, hundreds of thousands of little items. Each item is tiny, but processing the whole list is going to take several seconds of CPU time, during which it would be polite if we handled IO events (such as GUI interactions). No problem.. my @items = ("foo") x 1_000_000; my $governor = CPS::Governor::IOAsync->new( $loop, iterations => 100 ); $governor->kforeach( \...@items, sub { my ( $item, $knext ) = @_; process( $item ); goto &$knext; }, sub { say "Finished" } ); The Governor object here takes care of the iteration counting. Every 100 iterations it'll pause a moment and check IO::Async pending events. The way this would be implemented would be that the Governor's kwhile() method would use the $loop's idle event handling to call the next iteration, rather than invoke it immediately. This also lets us do such interesting things as: my @numbers = ( 1 .. 10 ); my $governor = CPS::Governor::IOAsync->new( $loop, iterations => 2 ); $governor->kforeach( \...@numbers, sub { print "A$_[0] "; goto &$_[1] }, sub {} ); $governor->kforeach( \...@numbers, sub { print "B$_[0] "; goto &$_[1] }, sub {} ); This would print A1 A2 B1 B2 A3 A4 B3 B4 A5 A6 B5 B6 A7 A8 B7 B8 A9 A10 B9 B10 The only real point of hesitation in my mind, though, is that of implementing control flow structures as methods on an object. This feels somehow unclean. Perhaps instead they can use the new lexical pragmas in 5.10; allowing a somewhat cleaner style of: use CPS qw( kforeach ); # kforeach here would use the "default" flat Governor { use CPS::Governor::IOAsync $loop, iterations => 10; kforeach( [ 1 .. 100 ], sub { my ( $item, $knext ) = @_; do_item( $item, on_done => $knext ); }, sub { say "Finished" } ); } Or perhaps being a pragma it ought to be all lowercase? What are the rules here? And finally there's nothing IO::Async'y about the whole thing. Simply implementing another kwhile() method would allow Governors such as use CPS::Governor::POE $kernel; use CPS::Governor::AnyEvent $loop; use CPS::Governor::GLib $maincontext; ... -- Paul "LeoNerd" Evans leon...@leonerd.org.uk ICQ# 4135350 | Registered Linux# 179460 http://www.leonerd.org.uk/
signature.asc
Description: PGP signature