Of course, apart from the "call-with-new-args" behaviour, having
Pythonic coroutines isn't noticably less powerful. Given:

    sub fibs ($a = 0 is copy, $b = 1 is copy) {
        loop {
            yield $b;
            ($a, $b) = ($b, $a+b);
        }
    }

we still have implicit iteration:

    for fibs() {
        print "Now $_ rabbits\n";
    }

and explicit iteration:

    my $iter = fibs();
    while <$iter> {
        print "Now $_ rabbits\n";
    }

and explicit multiple iteration:

    my $rabbits = fibs(3,5);
    my $foxes   = fibs(0,1);
    loop {
        my $r = <$rabbits>;
        my $f = <$foxes>;
        print "Now $r rabbits and $f foxes\n";
    }

and even explicitly OO iteration:

    my $iter = fibs();
    while $iter.next {
        print "Now $_ rabbits\n";
    }


And there's no reason that a coroutine couldn't produce an iterator object
with *two* (overloaded) C<next> methods, one of which took no arguments
(as in the above examples), and one of which had the same parameter list
as the coroutine, and which rebound the original parameters on the next
iteration.

For example, instead of the semantics I proposed previously:

    # Old proposal...

    sub pick_no_repeats (*@from_list) {
        my $seen;
        while (pop @from_list) {
            next when $seen;
            @from_list := yield $_;
            $seen |= $_;
        }
    }

    # and later:

    while pick_no_repeats( @values ) {
        push @values, some_calc($_);
    }


we could just write:

    # New proposal

    sub pick_no_repeats (*@from_list) {
        my $seen;
        while (pop @from_list) {
            next when $seen;
            yield $_;
            $seen |= $_;
        }
    }

    # and later:

    my $pick = pick_no_repeats( @values );
    while $pick.next(@values)  {
        push @values, some_calc($_);
    }


These semantics also rather neatly solve the problem of whether or
not to re-evaluate/re-bind the parameters each time a coroutine
is resumed. The rule becomes simple: if the iterator's C<next>
method is invoked without arguments, use the old parameters;
if it's invoked with arguments, rebind the parameters.

And the use of the <$foo> operator to mean $foo.next cleans up
teh syntax nicely.

I must say I rather like this formulation. :-)

Damian



Reply via email to