Idealnie, autor funkcji wolałby użyć
sub fact {
my ($n) = @_;
my $_fact; $_fact = sub {
my ($n, $prod) = @_;
return $prod if $n == 0;
return $_fact->($n-1, $n*$prod);
};
return $_fact->($n, 1);
}
Niestety, ma wyciek pamięci. Anon sub ma odniesienie do $_fact
, które zawiera odniesienie do anonimowego sub. $_fact
musiałaby zostać wyczyszczona, aby zerwać referencję przy wyjściu.
sub fact {
my ($n) = @_;
my $_fact;
$_fact = sub {
my ($n, $prod) = @_;
return $prod if $n == 0;
return $_fact->($n-1, $n*$prod);
};
my $rv;
my $e = eval { $rv = $_fact->($n, 1); 1 } ? undef : ([email protected] || 'Unknown');
$_fact = undef;
die $e if $e
return $rv;
}
Ale to jest UGLY! Jednym ze sposobów uniknięcia problemu jest użycie Y combinator. Znacznie prostszym sposobem na uniknięcie problemu jest przechowywanie odwołania do kodu w zmiennej pakietowej zamiast zmiennej leksykalnej (ponieważ tylko zmienne leksykalne są przechwytywane przez subs). Tak właśnie zrobiłeś kod. Należy pamiętać, że
*_fact = sub { ... };
jest w zasadzie wersji run-time z
sub _fact { ... }
Zarówno przypisać sub Kodeksu szczelinie symbolu _fact
.
Powiedział, 5.16 wprowadzono lepszą Fix:
use feature qw(current_sub);
sub fact {
my ($n) = @_;
my $_fact = sub {
my ($n, $prod) = @_;
return $prod if $n == 0;
return __SUB__->($n-1, $n*$prod);
};
return $_fact->($n, 1);
}
"Jaki jest dokładny Funkcja/cel * przed _fact" –
@ikegami jak o http://codepad.org/80KSqye4? –
Nie przecieka, ale jest kiepskim rozwiązaniem. Usuwa rekursję ogonową, która była oczywiście czynnikiem przewodnim w projektowaniu subwoofera. '$ n? $ n * fakt ($ n-1): 1 "wystarczałby inaczej. Wyeliminowanie rekursji ogona sprawia, że wszędzie jest ona nieefektywna. Zmiana zewnętrznej części na koniec za pomocą 'my $ rv = $ _fact (...); undef $ _fact; $ rv' byłoby bardziej odpowiednie. – ikegami