subrutinas sintaxis lenguaje ejemplos perl arguments subroutine

sintaxis - Cómo crear una subrutina Perl que acepte un bloque de código



sintaxis de perl (3)

Tengo un conjunto de subrutinas que se ven así:

sub foo_1($) { my $name = shift; my $f; run_something(); open($f, $name) or die ("Couldn''t open $name"); while (<$f>) { //Something for foo_1() } close($f); do_something_else(); }

Y tengo como cuatro o más que se ven iguales, lo único que cambia es el cuerpo del bloque while. Me gustaría resumir esto y dejar de copiar y pegar el código.

  • ¿Hay alguna forma de codificar una subrutina que acepte un bloque de código y la ejecute?

Para dar más contexto, las diferentes subrutinas foo son una Máquina de estados finitos (FSM) diferente que lee el contenido de diferentes archivos y alimenta los datos a una referencia de hash. Tal vez hay algo más inteligente que hacer que lo que estoy tratando de lograr.


Perl ofrece un sistema llamado prototipos de subrutinas que le permiten escribir subs de usuario que se analizan de forma similar a las funciones integradas. Los editores que desea emular son map , grep o sort que pueden tomar cada bloque como su primer argumento.

Para hacer eso con prototipos, usa un sub name (&) {...} donde & dice a perl que el primer argumento para la función es un bloque (con o sin sub ), o una subrutina literal /&mysub . El prototipo (&) especifica uno y solo un argumento, si necesita pasar múltiples argumentos después del bloque de código, puede escribirlo como (&@) que significa, un bloque de código seguido por una lista.

sub higher_order_fn (&@) { my $code = /&{shift @_}; # ensure we have something like CODE for (@_) { $code->($_); } }

Esa subrutina ejecutará el bloque pasado en cada elemento de la lista pasada. El /&{shift @_} parece un poco críptico, pero lo que hace es quitar el primer elemento de la lista, que debería ser un bloque de código. El &{...} desreferencia el valor como una subrutina (invocando cualquier sobrecarga), y luego el / inmediatamente toma la referencia al mismo. Si el valor fue una REF del CÓDIGO, entonces se devuelve sin cambios. Si se trataba de un objeto sobrecargado, se convierte en código. Si no se puede forzar a CODE, se produce un error.

Para llamar a esta subrutina, deberías escribir:

higher_order_fn {$_ * 2} 1, 2, 3; # or higher_order_fn(sub {$_ * 2}, 1, 2, 3);

El prototipo (&@) que le permite escribir el argumento como un bloque de map / grep solo funciona cuando se usa la función de orden superior como una función. Si lo está utilizando como método, debe omitir el prototipo y escribirlo de esta manera:

sub higher_order_method { my $self = shift; my $code = /&{shift @_}; ... $code->() for @_; } ... $obj->higher_order_method(sub {...}, ''some'', ''more'', ''args'', ''here'');


Quieres el & prototipo.

sub foo(&@) { my ($callback) = shift; ... $callback->(...); ... }

hace

foo { ... } ...;

equivalente a

foo(sub { ... }, ...);


sub bar { my ($coderef) = @_; ⁝ $coderef->($f, @arguments); ⁝ } bar(sub { my ($f) = @_; while … }, @other_arguments);

o tal vez un poco menos enredado con un coderef con nombre:

my $while_sub = sub { my ($f) = @_; while … ⁝ }; bar($while_sub, @other_arguments);

Editar : El libro Perl de orden superior está lleno de este tipo de programación.