programa - perl vs python
En Perl, ¿cómo puede una subrutina obtener un coderef que apunta a sí mismo? (5)
Creo que Sub::Current solucionará tu problema.
Para fines de aprendizaje, estoy jugando con la idea de crear programas basados en eventos en Perl y me di cuenta de que podría ser bueno si una subrutina registrada como un controlador de eventos pudiera, en caso de falla, programar otra llamada para un futuro hora. Hasta ahora, he llegado a algo como esto:
my $cb;
my $try = 3;
$cb = sub {
my $rc = do_stuff();
if (!$rc && --$try) {
schedule_event($cb, 10); # schedule $cb to be called in 10 seconds
} else {
do_other_stuff;
}
};
schedule_event($cb, 0); # schedule initial call to $cb to be performed ASAP
¿Hay alguna manera de que el código dentro del submarino pueda acceder al reflecto codificado de ese submarino para que yo pueda prescindir de usar una variable adicional? Me gustaría programar la llamada inicial de esta manera.
schedule_event( sub { ... }, 0);
Primero pensé en usar la caller(0)[3]
, pero esto solo me da un nombre de función, ( __ANON__
si no hay nombre), no una referencia de código que tiene una almohadilla adjunta.
Para obtener una referencia a la subrutina actual sin usar una variable adicional, puede usar una herramienta de programación funcional, el Y-combinator, que básicamente abstrae el proceso de creación del cierre. Aquí hay una versión perlish:
use Scalar::Util qw/weaken/;
sub Y (&) {
my ($code, $self, $return) = shift;
$return = $self = sub {$code->($self, @_)};
weaken $self; # prevent a circular reference that will leak memory
$return;
}
schedule_event( Y { my $self = shift; ... }, 0);
Si no cambia el $cb
nuevamente, puede usar eso. Si no, defina un escalar para mantener eso y no lo cambie nunca más. Por ejemplo:
my $cb = do {
my $sub;
$sub = sub { contents using $sub here }
}
Usando un combinador de punto fijo, puede escribir su función $ cb como si el primer argumento fuera la función misma:
sub U {
my $f = shift;
sub { $f->($f, @_) }
}
my $cb = sub {
my $cb = shift;
...
schedule_event(U($cb), 10);
...
}
schedule_event(U($cb), 0);
__SUB__
se ha agregado en 5.16, proporcionando esta usabilidad.