--- 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. 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(...) ? If No: How do you create a new context? Perhaps we need both: coro-as-verb to create a coro context on any arbitrary function, and coro-as-type to declare contexts in advance. > > (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. =Austin