Provided by: libsyntax-keyword-gather-perl_1.003002-1_all bug


       Syntax::Keyword::Gather - Implements the Perl 6 'gather/take' control structure in Perl 5


       version 1.003002


        use Syntax::Keyword::Gather;

        my @list = gather {
           # Try to extract odd numbers and odd number names...
           for (@data) {
              if (/(one|three|five|seven|nine)$/) { take qq{'$_'} }
              elsif (/^\d+$/ && $_ %2)            { take $_ }
           # But use the default set if there aren't any of either...
           take @defaults unless gathered;

       or to use the stuff that Sub::Exporter gives us, try

        # this is a silly idea
        use syntax gather => {
          gather => { -as => 'bake' },
          take   => { -as => 'cake' },

        my @vals = bake { cake (1...10) };


       Perl 6 provides a new control structure -- "gather" -- that allows lists to be constructed
       procedurally, without the need for a temporary variable. Within the block/closure
       controlled by a "gather" any call to "take" pushes that call's argument list to an
       implicitly created array.  "take" returns the number of elements it took.  This module
       implements that control structure.

       At the end of the block's execution, the "gather" returns the list of values stored in the
       array (in a list context) or a reference to the array (in a scalar context).

       For example, instead of writing:

        print do {
           my @wanted;
           while (my $line = <>) {
              push @wanted, $line  if $line =~ /\D/;
              push @wanted, -$line if some_other_condition($line);
           push @wanted, 'EOF';
           join q{, }, @wanted;

       instead we can write:

        print join q{, }, gather {
           while (my $line = <>) {
              take $line  if $line =~ /\D/;
              take -$line if some_other_condition($line);
           take 'EOF';

       and instead of:

        my $text = do {
           my $string;
           while (<>) {
              next if /^#|^\s*$/;
              last if /^__[DATA|END]__\n$/;
              $string .= $_;

       we could write:

        my $text = join q{}, gather {
           while (<>) {
              next if /^#|^\s*$/;
              last if /^__[DATA|END]__\n$/;
              take $_;

       There is also a third function -- "gathered" -- which returns a reference to the implicit
       array being gathered. This is useful for handling defaults:

        my @odds = gather {
           for @data {
              take $_ if $_ % 2;
              take to_num($_) if /[one|three|five|nine]$/;
           take (1,3,5,7,9) unless gathered;

       Note that -- as the example above implies -- the "gathered" function returns a special
       Perl 5 array reference that acts like a Perl 6 array reference in boolean, numeric, and
       string contexts.

       It's also handy for creating the implicit array by some process more complex than by
       simple sequential pushing. For example, if we needed to prepend a count of non-numeric

        my @odds = gather {
           for @data {
              take $_ if $_ %2;
              take to_num($_) if /[one|three|five|seven|nine]$/;
           unshift gathered, +grep(/[a-z]/i, @data);

       Conceptually "gather"/"take" is the generalized form from which both "map" and "grep"
       derive. That is, we could implement those two functions as:

        sub map (&@) {
          my $coderef = shift;
          my @list = @{shift @_};

          return gather {
             take $coderef->($_) for (@list)

        sub grep (&@) {
          my $coderef = shift;
          my @list = @{shift @_};

          return gather {
             do { take $_ if $coderef->($_) } for @list

       A "gather" is also a very handy way of short-circuiting the construction of a list. For
       example, suppose we wanted to generate a single sorted list of lines from two sorted
       files, but only up to the first line they have in common. We could gather the lines like

        my @merged_diff = gather {
           my $a = <$fh_a>;
           my $b = <$fh_b>;
           while (1) {
              if ( defined $a && defined $b ) {
                 if    ($a eq $b) { last }     # Duplicate means end of list
                 elsif ($a lt $b) { take $a; $a = <$fh_a>; }
                 else             { take $b; $b = <$fh_b>; }
              elsif (defined $a)  { take $a; $a = <$fh_a>; }
              elsif (defined $b)  { take $b; $b = <$fh_b>; }
              else                { last }

       If you like it really short, you can also "gather"/"take" $_ magically:

       my @numbers_with_two = gather {
           for (1..20) {
               take if /2/
           } }; # @numbers_with_two contains 2, 12, 20

       Be aware that $_ in Perl5 is a global variable rather than the current topic like in


       This module was forked from Damian Conway's Perl6::Gather for a few reasons.

       to avoid the slightly incendiary name
       to avoid the use of the Perl6::Exporter
       ~ doesn't overload to mean string context


       It would be nice to be able to code the default case as:

        my @odds = gather {
           for (@data) {
              take if $_ % 2;
              take to_num($_) if /(?:one|three|five|nine)\z/;
        } or (1,3,5,7,9);

       but Perl 5's "or" imposes a scalar context on its left argument.  This is arguably a bug
       and definitely an irritation.


       ·   Arthur Axel "fREW" Schmidt <>

       ·   Damian Conway


       This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt.

       This is free software; you can redistribute it and/or modify it under the same terms as
       the Perl 5 programming language system itself.