http://www.perlmonks.org?node_id=541775


in reply to recursive anonymous subroutines

What's wrong storing a reference to an anonymous inner sub in an anonymous outer closure?

Eg to create an recursive factorial subroutine:

#!/usr/bin/perl use strict; my $sub = do { my $this_sub; $this_sub = sub { my $factor = int(shift); return $factor > 1 ? &$this_sub($factor-1) * $factor : 1; }; }; print "factorial of 7 is ".&$sub(7)."\n";
This is localised and lends itself to functional usage, eg:
my @factorials = map {&{ my $this_sub; $this_sub = sub { my $factor = int(shift); return $factor > 1 ? &$this_sub($factor-1) * $factor : 1; }}($_)} (3,5,7,9); print "factorials: @factorials\n";
Update: see below for revised solution.

Replies are listed 'Best First'.
Re^2: recursive anonymous subroutines
by Anonymous Monk on Apr 08, 2006 at 21:51 UTC
    "What's wrong storing a reference to an anonymous inner sub in an anonymous outer closure?"
    It's a recursive, i.e. leaking, reference.
      It's a recursive, i.e. leaking, reference.

      Hmm... probably safer to keep the reference on the call stack, thus releasing it on exit.

      For example, adopting the convention that the reference is always passed as the first parameter:

      my @factorials = map { $_[0] ||= sub { my $factor = pop; return $factor > 1 ? &{$_[0]}($_[0],$factor-1) * $factor : 1; }; &{$_[0]}($_[0],$_)} (3,5,7,9);
      ..or..
      sub make_call { goto $_[0]; } my @factorials = map { make_call (sub { my $factor = $_[1]; return $factor > 1 ? make_call($_[0], $factor-1) * $factor : 1; }, $_); } (3,5,7,9);
        Very nice! I believe your make_call version will shortly become a new idiom in my code. Many thanks!
        Just thought I'd point out that this is an interesting reinvention of a previous post (though with one less level into the call stack due to the goto). Compare:
        # Your's: sub make_call { goto $_[0] } # Anonymonk's(slightly rearranged): sub Y { $_[0]->(@_) }
        Update: Well, it's more the same if you change your call to:
        make_call (sub { my $factor = $_[1]; return $factor > 1 ? $_[0]->($_[0], $factor-1) * $factor : 1; }, $_);