#!/usr/local/bin/perl use strict; use warnings; use v5.32; # From Chapter 7 of "Beginning Perl" by Curis "Ovic" Poe: # The make_fibonacci() subroutine returns an anonymous subroutine that # references the $current and $next variables declared in the # make_fibonacci() subroutine, but outside of the anonymous subroutine. # The $iterator variable contains a reference to this anonymous subroutine, # and it “remembers” the values of the $current and $next variables. Every # time it is invoked, it updates the values of $current and $next and # returns the next Fibonacci number. Eventually, you get to the for loop # that prints the first 10 Fibonacci numbers. You can pass the $iterator # variable to other subroutines just like any other variable, and it still # remembers its state. You can create several iterators with this same # subroutine, and each will have a separate copy of $current and $next. sub make_fibonacci { my ( $current, $next ) = ( 0, 1 ); return sub { my $fibonacci = $current; ( $current, $next ) = ( $next, $current + $next ); return $fibonacci; } } my $iterator = make_fibonacci(); for ( 1 .. 10 ) { my $fibonacci = $iterator->(); say $fibonacci; } # 0, 1, 1, 2, ..., 21, 34 say $iterator->(); # 55 say "--------------------"; my $iterator2 = make_fibonacci(); say $iterator2->() for ( 1 .. 5 ); # 0, 1, 1, 2, 3 say "--------------------"; # The example below is taken from Chapter 2 of "Object Oriented Perl" by # Damian Conway. # When the hop_along subroutine is called, it copies its three arguments # into lexical variables, sets up another lexical (i.e., $next) as a counter, # and then creates an anonymous sub-routine that uses the values in those # variables. The anonymous subroutine increments $next by $step each time # the subroutine is called, until the result is greater than $to. A reference # to the newly created anonymous subroutine is then returned. sub hop_along { my ( $from, $to, $step ) = @_; # unpack arguments my $next = $from - $step; # initialize counter my $closure_ref = sub { # the first time we call the iterator $closure_ref, $next is equal to # $from - $step as defined above. In subsequent calls, increments according # to $next += $step. $next += $step; # take a step return if ( $next > $to ); # we've reached the end # the next line sets the calling parameter $_[0] to equal to the $next that # is in the scope of this array. $_[0] is set as the calling parameter # which is transferred to the $next down below in the calling routine. $_[0] = $next; # otherwise, set new value return 1; # exit }; return $closure_ref; # return closure } # Normally, the lexical variables inside the call to hop_along (i.e., $from, # $to, $step, $next) would cease to exist when hop_along returned. But, # because the anonymous subroutine still needs access to them, Perl arranges # for them to live on in seclusion, accessible only by the anonymous # subroutine itself. Closures are a means of giving a subroutine its own # private memory — variables that persist between calls to that subroutine # and are accessible only to it. my $iterator3 = hop_along (1, 30, 7); # Create closure my $next; while ($iterator3->($next)) # Call closure { say $next; }