On May 4, 2005 06:22 pm, Rod Adams wrote:
> John Macdonald wrote:
> >On Wed, May 04, 2005 at 03:02:41PM -0500, Rod Adams wrote:
> >  
> >
> >>If there are good uses for coroutines that given/take does not address, 
> >>I'll gladly change my opinion. But I'd like to see some examples.
> >>FWIW, I believe that Patrick's example of the PGE returning matches 
> >>could be written with given/take (if it was being written in P6).
> >>    
> >>
> >
> >Um, I don't recall what given/take provides, so I may be only
> >addressing the limitations of lazy lists...
> >  
> >
> First off, it's gather/take, not given/take. My mistake. Oops.
> Here goes my understanding of gather/take:
> "gather" takes a block as an argument, and returns a lazy list object. 
> Inside that block, one can issue "take" commands, which "push" one or 
> more values onto the list. However, since it's all lazy, it only 
> executes the block when someone needs something off the list that 
> currently isn't there. And even then, it only executes the block up 
> until enough "take"s have happened to get the requested value. If the 
> block exits, the list is ended.

Strange.  The names gather/take suggest accepting values rather than
generating them (yet generating them onto the lizy list is what you
describe this code as doing).  I don't like the name "yield" either for the
same reason - it suggests that the data only goes one way while the
operation of transferrig control from one coroutine to another is a pair
has the first producing a value to the other (but also being ready to
accept a value in return when it gets resumed in turn).  Whether a
particular resume is passing data out, or accepting data in, or both,
is a matter of what your code happen to need at that moment.

> A simple example:
>   sub grep ($test, [EMAIL PROTECTED]) {
>     gather {
>       for @values -> $x {
>         take $x if $x ~~ $test;
>       }
>     }
>   }
> Since the block in question is in effect a closure, and gets called 
> whenever a new value to the lazy list is requested, I believe it 
> provides all of the generator aspects of coroutines. It could access 
> various up-scoped/global variables, thereby changing it's behavior 
> midcourse, if needed. You can create several versions of the same 
> generator, all distinct, and with separate "states", and easily keep 
> them separate. To create a new list, you call the function. To resume a 
> list, you ask for a value from the list it hasn't already created.

Asking for a value by scanning a lazy list provides no mechanism for
sending information to the routine that will provide that value.

For example, the parser for perl5 is written with contorted code because
it needs just such a feedback mechanism - the parser has to turn
characters into tokens differently depending upon the context.  If it was
written as a lazy list of tokens, there would have to be this feedback
done somehow.  (Is \1 one token or two?  In a string, it is one token for
the character with octal value 001 (or perhaps a part of the token that
is the entire string containing that character as only a portion), in a
substitute, it is one token that refers back to the first match, in open
expression code, it is two tokens representing a refernce operator and
the numeric value 1.  (POD and here-strings are other forms that
require feedback.)

> Once you have some of these lazy list functions made, pipelining them 
> together is trivial via "==>" or "<==".
> >For many simple uses generators are exactly what you need,
> >but they have limits.  A more powerful coroutine mechanism can
> >easily provide the simple forms (and, I would expect, without
> >any serious loss of performance).
> >
> I'll ask again for a couple examples of the non-generator uses, mostly 
> out of curiosity, but also to better evaluate the proposals being kicked 
> around in this thread.
> -- Rod Adams

Reply via email to