> --- Michael Lazzaro <[EMAIL PROTECTED]> wrote: > > > > On Wednesday, May 28, 2003, at 01:01 PM, Austin Hastings wrote: > > > Exampling: > > > > > > sub traverse(Hash $tree) { > > > return unless $tree; > > > > > > traverse $tree{left} if $tree{left}; > > > yield $tree{node}; > > > traverse $tree{right} if $tree{right}; > > > } > > > > > > my %hash is Tree; > > > my &cotrav := coro &traverse(%hash); > > > print $_ for <ctrav.resume>; > > > > > > my &thtrav := thread &traverse(%hash); > > > print $_ for <thtrav.resume>; > > > > > > Hmm. I think that having _anything_ on the caller side that has to > > change based on whether the called thing is a subroutine vs. a > > coroutine probably defeats one of the most central purposes of > > coroutines -- that nifty subroutine-like abstraction that makes it > > "just work". Consider, under Damian's latest model: > > > > for <foo()> {...} > > > > It doesn't matter whether foo() is a closure or function returning a > > list, lazy list, or iterator, or is a coroutine returning it's .next > > value. Which is excellent, and, I'd argue, the whole point; I'm not > > sure that we can have any coroutine syntax that _doesn't_ do that, > > can we? > > Given that I can say: > > sub do_foo {...} > my &foo := coro &do_foo; > > I can still provide the "transparent" behavior you're wanting. > > > But, as Luke pointed out, some of the other syntax required to make > > that work is isn't particularly friendly: > > > > coro pre_traverse(%data) { > > yield %data{ value }; > > yield $_ for <&_.clone(%data{ left })>; > > yield $_ for <&_.clone(%data{ right })>; > > } > > > If I work backwards, the syntax I'd _want_ for something like that > > would be much like Luke proposed: > > > > sub pre_traverse(%data) is coroutine { > > yield %data{ value }; > > pre_traverse( %data{ left } ); > > pre_traverse( %data{ right } ); > > } > > > > ... where the internal pre_traverses are yielding the _original_ > > pre_traverse. Whoa, though, that doesn't really work, because you'd > > have to implicitly do the clone, which screws up the normal iterator > > case! And I don't immediately know how to have a syntax do the right > > thing in _both_ cases. > > > > So, if I have to choose between the two, I think I'd rather iteration > > be easy than recursion be easy. If lines like > > > > yield $_ for <&_.clone(%data{ left })>; > > > > are too scary, we might be able to make a keyword that does that, > > like: > > > > sub pre_traverse(%data) is coroutine { > > yield %data{ value }; > > delegate pre_traverse( %data{ left } ); > > delegate pre_traverse( %data{ right } ); > > } > > > > Maybe. But in truth, that seems no more intuitive than the first. > > Q: Can you "yield" from a subsubroutine? > > If no, then yield=>coro at compile time. I don't care much for this > because it puts too much emphasis on remaining "in" the coroutine, > precluding me from distributing functionality. John MacDonald has given > several examples of this.
Agreed. I want to be able to distribute functionality. This is isomorphic with recursion. > Q: If you recurse, does it automatically create a new coro context? > > If Yes: We need a way to recurse in context. Perhaps by saying > &_.recurse(...) ? Obviously, that's not what I advocate. > If No: How do you create a new context? Like this: # countcounter(4) yields 0 0 1 0 0 1 2 3 coro countcounter($n) { for 0..$n-1 -> $c { my $counter = coro { countcounter($c) }; yield $_ for <$counter>; yield $c; } } Yay for objects! The only thing declaring countcounter as a coro gets you is the ability to use &countcounter itself as an iterator... and some documentation. Since it takes an argument, it would probably be just as useful as a sub. > > (s/coroutine/thread/g for the same rough arguments, e.g. "why should > > the caller care if what they're doing invokes parallelization, so > > long as it does the right thing?") > > Global variables. Threads __never__ do the right thing. Hopefully Perl 6 will change that. Luke