1Syntax::Keyword::GatherU(s3e)r Contributed Perl DocumentaStyinotnax::Keyword::Gather(3)
2
3
4

NAME

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

VERSION

10       version 1.003002
11

SYNOPSIS

13        use Syntax::Keyword::Gather;
14
15        my @list = gather {
16           # Try to extract odd numbers and odd number names...
17           for (@data) {
18              if (/(one|three|five|seven|nine)$/) { take qq{'$_'} }
19              elsif (/^\d+$/ && $_ %2)            { take $_ }
20           }
21           # But use the default set if there aren't any of either...
22           take @defaults unless gathered;
23        }
24
25       or to use the stuff that Sub::Exporter gives us, try
26
27        # this is a silly idea
28        use syntax gather => {
29          gather => { -as => 'bake' },
30          take   => { -as => 'cake' },
31        };
32
33        my @vals = bake { cake (1...10) };
34

DESCRIPTION

36       Perl 6 provides a new control structure -- "gather" -- that allows
37       lists to be constructed procedurally, without the need for a temporary
38       variable. Within the block/closure controlled by a "gather" any call to
39       "take" pushes that call's argument list to an implicitly created array.
40       "take" returns the number of elements it took.  This module implements
41       that control structure.
42
43       At the end of the block's execution, the "gather" returns the list of
44       values stored in the array (in a list context) or a reference to the
45       array (in a scalar context).
46
47       For example, instead of writing:
48
49        print do {
50           my @wanted;
51           while (my $line = <>) {
52              push @wanted, $line  if $line =~ /\D/;
53              push @wanted, -$line if some_other_condition($line);
54           }
55           push @wanted, 'EOF';
56           join q{, }, @wanted;
57        };
58
59       instead we can write:
60
61        print join q{, }, gather {
62           while (my $line = <>) {
63              take $line  if $line =~ /\D/;
64              take -$line if some_other_condition($line);
65           }
66           take 'EOF';
67        }
68
69       and instead of:
70
71        my $text = do {
72           my $string;
73           while (<>) {
74              next if /^#|^\s*$/;
75              last if /^__[DATA|END]__\n$/;
76              $string .= $_;
77           }
78           $string;
79        };
80
81       we could write:
82
83        my $text = join q{}, gather {
84           while (<>) {
85              next if /^#|^\s*$/;
86              last if /^__[DATA|END]__\n$/;
87              take $_;
88           }
89        };
90
91       There is also a third function -- "gathered" -- which returns a
92       reference to the implicit array being gathered. This is useful for
93       handling defaults:
94
95        my @odds = gather {
96           for @data {
97              take $_ if $_ % 2;
98              take to_num($_) if /[one|three|five|nine]$/;
99           }
100           take (1,3,5,7,9) unless gathered;
101        }
102
103       Note that -- as the example above implies -- the "gathered" function
104       returns a special Perl 5 array reference that acts like a Perl 6 array
105       reference in boolean, numeric, and string contexts.
106
107       It's also handy for creating the implicit array by some process more
108       complex than by simple sequential pushing. For example, if we needed to
109       prepend a count of non-numeric items:
110
111        my @odds = gather {
112           for @data {
113              take $_ if $_ %2;
114              take to_num($_) if /[one|three|five|seven|nine]$/;
115           }
116           unshift gathered, +grep(/[a-z]/i, @data);
117        }
118
119       Conceptually "gather"/"take" is the generalized form from which both
120       "map" and "grep" derive. That is, we could implement those two
121       functions as:
122
123        sub map (&@) {
124          my $coderef = shift;
125          my @list = @{shift @_};
126
127          return gather {
128             take $coderef->($_) for (@list)
129          };
130        }
131
132        sub grep (&@) {
133          my $coderef = shift;
134          my @list = @{shift @_};
135
136          return gather {
137             do { take $_ if $coderef->($_) } for @list
138          };
139        }
140
141       A "gather" is also a very handy way of short-circuiting the
142       construction of a list. For example, suppose we wanted to generate a
143       single sorted list of lines from two sorted files, but only up to the
144       first line they have in common. We could gather the lines like this:
145
146        my @merged_diff = gather {
147           my $a = <$fh_a>;
148           my $b = <$fh_b>;
149           while (1) {
150              if ( defined $a && defined $b ) {
151                 if    ($a eq $b) { last }     # Duplicate means end of list
152                 elsif ($a lt $b) { take $a; $a = <$fh_a>; }
153                 else             { take $b; $b = <$fh_b>; }
154              }
155              elsif (defined $a)  { take $a; $a = <$fh_a>; }
156              elsif (defined $b)  { take $b; $b = <$fh_b>; }
157              else                { last }
158           }
159        }
160
161       If you like it really short, you can also "gather"/"take" $_ magically:
162
163       my @numbers_with_two = gather {
164           for (1..20) {
165               take if /2/
166           } }; # @numbers_with_two contains 2, 12, 20
167
168       Be aware that $_ in Perl5 is a global variable rather than the current
169       topic like in Perl6.
170

HISTORY

172       This module was forked from Damian Conway's Perl6::Gather for a few
173       reasons.
174
175       to avoid the slightly incendiary name
176       to avoid the use of the Perl6::Exporter
177       ~ doesn't overload to mean string context
178

BUGS AND IRRITATIONS

180       It would be nice to be able to code the default case as:
181
182        my @odds = gather {
183           for (@data) {
184              take if $_ % 2;
185              take to_num($_) if /(?:one|three|five|nine)\z/;
186           }
187        } or (1,3,5,7,9);
188
189       but Perl 5's "or" imposes a scalar context on its left argument.  This
190       is arguably a bug and definitely an irritation.
191

AUTHORS

193       •   Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>
194
195       •   Damian Conway
196
198       This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt.
199
200       This is free software; you can redistribute it and/or modify it under
201       the same terms as the Perl 5 programming language system itself.
202
203
204
205perl v5.34.0                      2021-07-22        Syntax::Keyword::Gather(3)
Impressum