fork download
  1. #!/usr/bin/perl
  2.  
  3. # Idiom #319 generator functions
  4.  
  5. use feature 'say';
  6. use strict;
  7.  
  8. # predeclare _upto with prototype (&) so it expects an anonymous sub
  9. # without this, the iterator won't work inside a foreach loop (only while)
  10. # see https://p...content-available-to-author-only...l.org/perlsub#Prototypes
  11. sub _upto (&) { return $_[0]; }
  12.  
  13. # define a closure over $start and $end
  14. # see https://p...content-available-to-author-only...l.org/perlfaq7#What%27s-a-closure?
  15. sub upto {
  16. my ($start, $end) = @_;
  17.  
  18. my $n = $start;
  19.  
  20. return _upto {
  21. # in an array context, return list $start..$end
  22. # in scalar context"
  23. # if we've reached the end, reset $n to $start and return an empty list
  24. # (which in scalar context will be taken as false and stop the loop)
  25. # otherwise increment $n and return it
  26. wantarray ? $start .. $end :
  27. $n > $end ? ($n = $start, ()) :
  28. $n++
  29. ;
  30. };
  31. }
  32.  
  33. my $it = upto(3, 5);
  34.  
  35. print 'foreach:';
  36. foreach ( $it->() ) { print ' ' . $_ }
  37. print "\n";
  38.  
  39. $it = upto(2, 6);
  40.  
  41. print 'while: ';
  42. while ( my $n = $it->() ) { print ' ' . $n }
  43. print "\n";
  44.  
  45. # In array context, upto can be used to generate a range.
  46. # For that it uses perl's .. operator to generate an actual
  47. # list of numbers, So this use case isn't an example of an
  48. # iterator. The functionality is provided in upto just so it
  49. # would be a bit more generally useful.
  50. my $range = upto(7, 11);
  51. print 'list context: ';
  52. my @list = $range->();
  53. print join ' ', @list;
  54. print "\n";
  55.  
Success #stdin #stdout 0.01s 5436KB
stdin
Standard input is empty
stdout
foreach: 3 4 5
while:   2 3 4 5 6
list context: 7 8 9 10 11