Author: lwall Date: 2010-02-17 02:01:45 +0100 (Wed, 17 Feb 2010) New Revision: 29760
Modified: docs/Perl6/Spec/S04-control.pod Log: [S04] bring gather/take description more in line with modern realities Modified: docs/Perl6/Spec/S04-control.pod =================================================================== --- docs/Perl6/Spec/S04-control.pod 2010-02-16 23:43:09 UTC (rev 29759) +++ docs/Perl6/Spec/S04-control.pod 2010-02-17 01:01:45 UTC (rev 29760) @@ -13,8 +13,8 @@ Created: 19 Aug 2004 - Last Modified: 17 Dec 2009 - Version: 93 + Last Modified: 16 Feb 2010 + Version: 94 This document summarizes Apocalypse 4, which covers the block and statement syntax of Perl. @@ -683,28 +683,40 @@ =head2 The C<gather> statement prefix X<gather>X<take> -A variant of C<do> is C<gather>. Like C<do>, it is followed by a -statement or block, and executes it once. Unlike C<do>, it evaluates -the statement or block in sink (void) context; its return value is instead -specified by calling the C<take> list prefix operator one or more times -within the dynamic scope of the C<gather>. The C<take> function's -signature is like that of C<return>; it merely wraps up a C<Parcel> -of its arguments without imposing any additional constraints (in the -absence of context propagation by the optimizer). The value returned -by the C<take> to its own context is that same C<Parcel> object (which -is ignored when the C<take> is in sink context). Regardless of the -C<take>'s context, the C<Parcel> object is also added to the list of -values being gathered, which is returned by the C<gather> in the form -of a lazy list of C<Parcel>s, with each element corresponding to one C<take> -parcel. (A C<Parcel>s is normally flattened when bound into slurpy context, -but when bound into a slice context, the C<Parcel> objects become real -sublists. The eventual binding context thus determines whether to -throw away or keep the groupings resulting from each individual C<take> call.) +A variant of C<do> is C<gather>. Like C<do>, it is followed by a statement +or block, and executes it once. Unlike C<do>, it evaluates the statement or +block in sink (void) context; its return value is instead specified by calling +the C<take> list prefix operator one or more times within the dynamic scope of +the C<gather>. The C<take> function's signature is like that of C<return>; +while having the syntax of a list operator, it merely returns a single item +which if, if you return multiple items in a comma list, be wrapped up in a +C<Parcel> object. No additional constraints are enforce by context, since +all context is lazy in Perl 6. The flattening or non-flattening of any such +returned C<Parcel> will be dependent on how the gather's return iterator is +iterated (with .get vs .getarg). +The value returned by the C<take> to the C<take>'s own context is +that same returned object (which is ignored when the C<take> is in +sink context). Regardless of the C<take>'s immediate context, the +object returned is also added to the list of values being gathered, +which is returned by the C<gather> in the form of a lazy list (that +is, an iterator, really), with each element of that list corresponding +to one C<take> object (either a C<Parcel> or any other single object +serving as a degenerate parcel). + +Any C<Parcel>s in the returned list are normally flattened when bound +into slurpy context. When bound into a slice context, however, +the C<Parcel> objects become real C<Seq> objects that keep their +identity as discrete sublists. The eventual binding context thus +determines whether to throw away or keep the groupings resulting from +each individual C<take> call. Since most list contexts are flat +rather than sliced, the boundaries between individual C<take> +calls usually disappear. + Because C<gather> evaluates its block or statement in sink context, this typically causes the C<take> function to be evaluated in sink context. However, a C<take> function that is not in sink context -gathers its arguments I<en passant> and also returns them unchanged. +gathers its return objects I<en passant> and also returns them unchanged. This makes it easy to keep track of what you last "took": my @uniq = gather for @list { @@ -720,24 +732,24 @@ my @y; @x = gather for 1..2 { # flat context for list of parcels - my $x = take $_, $_ * 10; # item context for individual parcel - push @y, $x; + my ($y) := take $_, $_ * 10; # item context promotes parcel to seq + push @y, $y; } - # @x contains 4 Ints: 1,10,2,20 - # @y contains 2 Parcels: (1,10),(2,20) + # @x contains 4 Ints: 1,10,2,20 flattened by list assignment to @x + # @y contains 2 Seqs: Seq(1,10),Seq(2,20) sliced by binding to positional $y -Likewise, we can just remember the gather's result by binding and -later coerce it: +Likewise, we can just remember the gather's result parcel by binding and +later coercing it: - $c := gather for 1..2 { + my |$c := gather for 1..2 { take $_, $_ * 10; } # $c.flat produces 1,10,2,20 -- flatten fully into a list of Ints. - # $c.slice produces (1,10),(2,20) -- list of Parcels, a 2-D list. - # $c.item produces ((1,10),(2,20)) -- the saved Parcel itself as one item in item context. + # $c.slice produces Seq(1,10),Seq(2,20) -- list of Seqs, a 2-D list. + # $c.item produces Seq((1,10),(2,20)) -- coerced to Seq of unresolved Parcels Note that the C<take> itself is in sink context in this example because -the C<for> loop is in sink context. +the C<for> loop is in the sink context provided inside the gather. A C<gather> is not considered a loop, but it is easy to combine with a loop statement as in the examples above.