Re: Converting a Perl 5 "pseudo-continuation" to Perl 6

2009-01-02 Thread Aristotle Pagaltzis
* Geoffrey Broadwell  [2009-01-01 21:40]:
> In the below Perl 5 code, I refactored to pull the two halves of the PID
> file handling out of init_server(), but to do so, I had to return a sub
> from pid_file_handler() that acted as a "continuation".  The syntax is a
> bit ugly, though.  Is there a cleaner way to this in Perl 6?
>
> ##
> sub init_server {
> my %options  = @_;
>
> # ...
>
> # Do top (pre-daemonize) portion of PID file handling.
> my $handler = pid_file_handler($options{pid_file});
>
> # Detach from parent session and get to clean state.
> become_daemon();
>
> # Do bottom (post-daemonize) portion of PID file handling.
> $handler->();
>
> # ...
> }
>
> sub pid_file_handler {
> # Do top half (pre-daemonize) PID file handling ...
> my $filename = shift;
> my $basename = lc $BRAND;
> my $PID_FILE = $filename || "$PID_FILE_DIR/$basename.pid";
> my $pid_file = open_pid_file($PID_FILE);
>
> # ... and return a "continuation" on the bottom half (post-daemonize).
> return sub {
> $MASTER_PID  =  $$;
> print $pid_file $$;
> close $pid_file;
> };
> }
> ##
>
> When I asked this question on #perl6, pmurias suggested using
> gather/take syntax, but that didn't feel right to me either --

> it's contrived in a similar way to using a one-off closure.

Contrived how? I always found implicit continuations distasteful
in the same way that `each` and the boolean flip-flop are bad in
Perl 5: because they tie program state to a location in the code.
When there is state, it should be passed around explicitly. So I
think the return-a-closure solution is actually ideal.

F.ex. it keeps you entirely clear of the troublesome question of
when a subsequent call should restart the sub from the beginning
or resume it – should that happen when identical arguments are
passed? Or when no arguments are passed? Are there any rules
about the proximity of the calls in the code? Or does the
coroutine state effectively become global state (like with `each`
and `pos` in Perl 5)?

When you have an explicit entity representing the continuation,
all of these questions resolve themselves in at once: all calls
to the original routine create a new continuation, and all calls
via the state object are resumptions. There is no ambiguity or
subtlety to think about.

So from the perspective of the caller, I consider the “one-off”
closure ideal: the first call yields an object that can be used
to resume the call.

However, I agree that having to use an extra block inside the
routine and return it explicity is suboptimal. It would be nice
if there was a `yield` keyword that not only threw a resumable
exception, but also closed over the exception object in a
function that, when called, resumes the original function.

That way, you get this combination:

sub pid_file_handler ( $filename ) {
# ... top half ...
yield;
# ... bottom half ...
}

sub init_server {
# ...
my $write_pid = pid_file_handler( $options );
become_daemon();
$write_pid();
# ...
}

Regards,
-- 
Aristotle Pagaltzis // 


Re: Coroutines in Perl 6 (Was: Re: Converting a Perl 5 "pseudo-continuation" to Perl 6)

2009-01-02 Thread Daniel Ruoso
Em Sex, 2009-01-02 às 08:34 -0300, Daniel Ruoso escreveu:
>   token routine_def: {...}

Actually, I was just looking at STD, and the correct token would be

  token routine_declarator:coro {   }

I was also looking at the spec files, and I realized that DRAFT S17
mentions coroutines, but its definition is a bit different then the one
I suggested, and the example poses a good reason:

  coro dbl { yield $_ * 2; yield $_; };
  (1..4).map:{ dbl($_) }
  # should result in 2 2 6 4

This example suggests that it will not install an alias in the caller
scope, but the code object itself stores its state.

The other difference is that falling out of a coro makes it restart
immediatly without returning any value (this one is a bit weird, I'd
expect it to return the last statement on the routine as well).

But one way or another yield (yes, I wrote it wrong in the previous
post) is still implemented as a control exception that is caught by the
implicit CONTROL block of the coro.

daniel



Re: Converting a Perl 5 "pseudo-continuation" to Perl 6

2009-01-02 Thread Larry Wall
On Fri, Jan 02, 2009 at 06:06:31PM -0800, Geoffrey Broadwell wrote:
: Meaning, the gather/take syntax doesn't make much sense, because we're
: not "gathering" anything; the PID file handler has nothing to return.
: We'd only be using it for the "side effect" of being able to pause the
: callee's execution and resume it later.

Leaving aside for the moment the question of how much we want mere
mortals to know about continuations when normal closures would do,
I think you're falling into a kind of P5Think here, that all forms
of nothing are equivalent.  A take always returns a Capture object,
so at minimum you're gathering a list of Captures, even if they're
empty.  If you like, you could also think of gathering continuations
or closures, depending on whether the object you take closes over
return context or just the rest of the current call.

In any case, I dislike the overloading of the function interface that
happens with many standard coroutine designs.  That's why gather/take
is orthogonal to the function call interface.

As for syntactic relief, that will always be a macro away in Perl 6,
if you really want it.  But I think "return {...}" and "take {...}"
are nice, explicit idioms for returning a closure, and we've gone to
some pains in Perl 6 to make a bare block behave that way without a
keyword, so I'm not in a hurry to huffmanize away a mere two characters
for what what many readers would view as a form of obfuscation.

As for true reusable continuations, I'm not opposed to having them
available in the language per se, but they're hard to implement on some
architectures, and I'll certainly frown on any attempt to confuse them
with either normal closures or even single-use continuations in the
minds of mere mortals.  Using bare continuations where gather/take or
closures will do is like throwing out your steak knives because they
duplicate the functionality of your chain saw.  :)

Larry


Coroutines in Perl 6 (Was: Re: Converting a Perl 5 "pseudo-continuation" to Perl 6)

2009-01-02 Thread Daniel Ruoso
Em Qui, 2009-01-01 às 12:34 -0800, Geoffrey Broadwell escreveu:
> In the below Perl 5 code, I refactored to pull the two halves of the PID
> file handling out of init_server(), but to do so, I had to return a sub
> from pid_file_handler() that acted as a "continuation".  The syntax is a
> bit ugly, though.  Is there a cleaner way to this in Perl 6?

Well,

If the STD Perl 6 doesn't support that, you can always declare a
sub-grammar that implements a 

  token routine_def: {...}

then you have something in the lines of:

  coro pid_file_handler {
  ... # first half
  yeld $something;
  ... # second half
  }

It's even easy to implement how it should work. Basically, yeld throws a
resumable control exception, the implicit "CONTROL" block of the routine
will then contain the code to handle that exception by aliasing the coro
in that state in the caller lexical scope, overriding the current
definition. And once the routine is called again, and returns or leaves,
you simply re-binds to the original routine. 

The above solution assumes a coro state is only available in the same
lexical scope as the first call, which may be a good idea to avoid
action-at-a-distance.

But maybe we even convince larry to push that into STD... since it's
such a nice feature...

daniel