Re: Iterative anonymous subroutines
by stvn (Monsignor) on Dec 13, 2005 at 17:56 UTC
|
You can also solve this problem using a combination of a fixed point combinator (don't worry it's not as complex as it sounds) and currying.
Basically your problem is that you have a un-nameable subroutine which you want to recurse with. The problem is you are trying to call your subroutine by name, which is not possible since it's name can never be in the proper scope. The other option then is to call-by-value instead. In order to accomplish this, all you need to do is alter your anon-subroutine to take an additional parameter, which is the function you wish to call in the recursion. It might look something like this:
my $anon = sub {
my $func = shift;
my $count = shift;
if ($count--) {
print "Iterating\n";
$func->($count);
}
};
Now when you want to call this sub, you have to pass the sub itself as it's first parameter, and now you have your recursion.
Of course, this is most likely inconvient to have to do this. Fear not! Currying to the rescue! Just do this:
my $counter = sub { $anon->($anon, shift) };
And return $counter instead of $anon, and you have exactly what you are looking for.
Hope this helps :)
| [reply] [d/l] [select] |
Re: Iterative anonymous subroutines
by ikegami (Patriarch) on Dec 13, 2005 at 17:14 UTC
|
The proper word is recursive, not iterative. Iterative means something else.
The error occurs because the my hasn't occured at the time where $anon is used. (Assignments are processed right to left.) Therefore, the sub uses the package variable $main::anon. Cause the my to occur first by seperating the my from the assignment:
my $anon;
$anon = sub {
my $count = shift;
if ($count--) {
print "Iterating\n";
$anon->($count);
}
};
$anon->(4);
Update: Elaborated on the problem. | [reply] [d/l] [select] |
|
|
That's a guaranteed memory leak. You'll need to Scalar::Util::weaken $anon at some point to break the closure's circular reference.
| [reply] |
|
|
aye. Refer to the posts by demerphq and stvn for solutions that don't leak.
| [reply] |
|
|
The error occurs because the my hasn't occured at the time where $anon is used. (Assignments are processed right to left.)
Not exactly; the problem isn't the run-time effect of my not having occurred, it's with the compile-time effect.
my() "returns" (not exactly, since it's a declarator, not a function) the new lexical and that "returned" SV can be used in the current statement, but for purposes of compiling other mentions of the lexical of that name, the lexical's scope only begins with the following statement.
This can be seen with
perl -we'$foo = 2; print((my $foo=4),$foo)'
</c>
printing 42, not 44.
| [reply] [d/l] |
|
|
my $x = $x + 5;
Both $x refer to the same storage location (the same variable). To get the perl5 behavior you have to say something like:
my $x = $OUTER::x + 5;
| [reply] [d/l] [select] |
Re: Iterative anonymous subroutines
by friedo (Prior) on Dec 13, 2005 at 17:12 UTC
|
What you describe is recursive, not iterative. It won't work because as you noted $anon is not defined until the end of the statement, and as far as I know a subroutine can not be a closure on itself. Perhaps if you explained why you're attempting such an odd thing, we could provide a better way to do it. | [reply] [d/l] |
|
|
local *recursive=sub { ... recursive(...); };
This keeps the self references "soft" and means that when it goes out of scope the sub will be freed. Doing it via lexicals is not correct
my $recursive;
$recursive=sub{ ... $recursive->(...); };
as it will leak. (Meaning the sub referenced by $recursive will not be freed until global destruction.)
---
$world=~s/war/peace/g
| [reply] [d/l] [select] |
|
|
See also Sub::Recursive which handles all that for you in a clean way.
use Sub::Recursive;
my $recursive = recursive { ... $REC->(...) ... };
| [reply] [d/l] |
Re: Iterative anonymous subroutines
by Anonymous Monk on Dec 13, 2005 at 17:13 UTC
|
my $anon;
$anon = sub {
my $count = shift;
if ($count--) {
print "Iterating\n";
$anon->($count);
}
};
| [reply] [d/l] |
Re: Iterative anonymous subroutines
by blazar (Canon) on Dec 14, 2005 at 09:08 UTC
|
| [reply] |
|
|
| [reply] |