The trick here is to return a closure from a generator function. Below is a complete working example. However the salient bit is returning refs to $cont and $foo from the generator function, and dereferencing them in the caller to initialize or change them.
package Foobar;
sub _setup_xforms {
my ($cont, $foo);
return (\$cont, \$foo, {
xform1 => sub { printf("Level %d,foo=%s\n", $cont, $foo);
+},
});
};
sub transform {
my ($self, $cont) = @_;
my ($cont_ref, $foo_ref, $xforms) = _setup_xforms();
$$cont_ref //= $cont; # //= to convince you it's not still set
for my $xform (values %$xforms) {
$$foo_ref //= 0; # //= as above
$xform->();
$$foo_ref++;
$self->transform($cont + 1) if ($cont < 5);
print "Level $cont done, foo=$$foo_ref\n";
}
}
sub new { bless({},'Foobar') }
my $foo = new Foobar( id => 1 );
$foo->transform(0);
This produces the following output:
Level 0,foo=0
Level 1,foo=0
Level 2,foo=0
Level 3,foo=0
Level 4,foo=0
Level 5,foo=0
Level 5 done, foo=1
Level 4 done, foo=1
Level 3 done, foo=1
Level 2 done, foo=1
Level 1 done, foo=1
Level 0 done, foo=1