CPS

 view release on metacpan or  search on metacpan

lib/CPS.pm  view on Meta::CPAN

=head2 kseq( @bodies, $k )

This CPS function takes a list of function bodies and calls them each, one at
a time in sequence. Each is given a continuation to invoke, which will cause
the next body to be invoked. When the last body has invoked its continuation,
the main continuation C<$k> is invoked.

 $body->( $kdone )
   $kdone->()

 $k->()

A benefit of this is that it allows a long operation that uses many
continuation "pauses", to be written without code indenting further and
further to the right. Another is that it allows easy skipping of conditional
parts of a computation, which would otherwise be tricky to write in a CPS
form. See the EXAMPLES section.

=cut

sub gkseq
{
   my ( $gov, @bodies ) = @_;
   my $k = pop @bodies;

   my $enter = $gov->can('enter') or croak "Governor cannot ->enter";

   while( @bodies ) {
      my $nextk = $k;
      my $b = pop @bodies;
      $k = sub {
         @_ = ( $gov, $b, $nextk );
         goto &$enter;
      };
   }

   @_ = ();
   goto &$k;
}

=head1 GOVERNORS

All of the above functions are implemented using a loop which repeatedly calls
the body function until some terminating condition. By controlling the way
this loop re-invokes itself, a program can control the behaviour of the
functions.

For every one of the above functions, there also exists a variant which takes
a L<CPS::Governor> object as its first argument. These functions use the
governor object to control their iteration.

 kloop( \&body, $k )
 gkloop( $gov, \&body, $k )

 kforeach( \@items, \&body, $k )
 gkforeach( $gov, \@items, \&body, $k )

 etc...

In this way, other governor objects can be constructed which have different
running properties; such as interleaving iterations of their loop with other
IO activity in an event-driven framework, or giving rate-limitation control on
the speed of iteration of the loop.

=cut

# The above is a lie. The basic functions provided are actually the gk*
# versions; we wrap these to make the normal k* functions by passing a simple
# governor.
sub _governate
{
   my $pkg = caller;
   my ( $func, $name ) = @_;

   my $default_gov = CPS::Governor::Simple->new;

   no strict 'refs';

   my $code = $pkg->can( $func ) or croak "$pkg cannot $func()";
   *{$pkg."::$name"} = subname $name => sub {
      unshift @_, $default_gov;
      goto &$code;
   };
}

_governate "g$_" => $_ for @CPS_PRIMS;

=head1 CPS UTILITIES

These function names do not begin with C<k> because they are not themselves
CPS primatives, but may be useful in CPS-oriented code.

=cut

=head2 $kfunc = liftk { BLOCK }

=head2 $kfunc = liftk( \&func )

Returns a new CODE reference to a CPS-wrapped version of the code block or 
passed CODE reference. When C<$kfunc> is invoked, the function C<&func> is
called in list context, being passed all the arguments given to C<$kfunc>
apart from the last, expected to be its continuation. When C<&func> returns,
the result is passed into the continuation.

 $kfunc->( @func_args, $k )
    $k->( @func_ret )

The following are equivalent

 print func( 1, 2, 3 );

 my $kfunc = liftk( \&func );
 $kfunc->( 1, 2, 3, sub { print @_ } );

Note that the returned wrapper function only has one continuation slot in its
arguments. It therefore cannot be used as the body for C<kloop()>,
C<kforeach()> or C<kgenerate()>, because these pass two continuations. There
does not exist a "natural" way to lift a normal call/return function into a
CPS function which requires more than one continuation, because there is no
way to distinguish the different named returns.



( run in 0.776 second using v1.01-cache-2.11-cpan-96521ef73a4 )