Syntax...:Gather(3pm)
π Syntax::Keyword::Gather π
okay bestie, welcome to Syntax...:Gather(3pm) β this is a Perl 5 module that implements the Perl 6 gather/take control structure, and it is so much nicer than pushing into a temp array like a Victorian orphan. ngl, it's giving main character energy. π«Ά
β¨ NAME β¨
Syntax::Keyword::Gather β bestie, this implements the Perl 6 gather/take control structure in Perl 5. periodt. π
πΈ VERSION πΈ
version 1.003002
π¦ SYNOPSIS π¦
okay so the basic vibe is this:
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, if you wanna use the stuff that Sub::Exporter gives us, try this. (the comment in the original says it's a silly idea, and honestly bestie, they're right π)
# this is a silly idea
use syntax gather => {
gather => { -as => 'bake' },
take => { -as => 'cake' },
};
my @vals = bake { cake (1...10) };
π DESCRIPTION π
Perl 6 provides a new control structure β gather β that lets you construct lists procedurally, without needing a temporary variable. no cap. Inside the block/closure controlled by a gather, any call to take pushes that call's argument list to an implicitly created array. And take returns the number of elements it took. This module implements that control structure. iconic behaviour honestly.
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 this whole sad little do block:
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 this, which is so much cuter:
print join q{, }, gather {
while (my $line = <>) {
take $line if $line =~ /\D/;
take -$line if some_other_condition($line);
}
take 'EOF';
}
and instead of this:
my $text = do {
my $string;
while (<>) {
next if /^#|^\s*$/;
last if /^__[DATA|END]__\n$/;
$string .= $_;
}
$string;
};
we could write this:
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, like:
my @odds = gather {
for @data {
take $_ if $_ % 2;
take to_num($_) if /[one|three|five|nine]$/;
}
take (1,3,5,7,9) unless gathered;
}
π Heads up bestie β 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 items:
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 this:
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
β οΈ bestie, be aware that $_ in Perl5 is a global variable rather than the current topic like in Perl6. it's not giving what Perl 6 is giving. π
π HISTORY π
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
π BUGS AND IRRITATIONS π
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. π«
π AUTHORS π
- Arthur Axel "fREW" Schmidt
<frioux+cpan@gmail.com> - Damian Conway
π§ COPYRIGHT AND LICENSE π§
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.
okay that's the whole page bestie!! πβ¨π¦ this one shipped as part of perl v5.36.0, dated 2022-12-04, under the manual page name Syntax...:Gather(3pm) β go forth and gather, you absolute icon π ππΈ
π¦ where this page comes from
- debian bookworm: libsyntax-keyword-gather-perl 1.003002-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libsyntax-keyword-gather-perl 1.003002-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libsyntax-keyword-gather-perl 1.003002-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libsyntax-keyword-gather-perl 1.003002-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libsyntax-keyword-gather-perl 1.003002-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms