Clausuras

El concepto de clausura es una noción bien conocida en el mundo de la programación funcional. Cuando se define una subrutina en un determinado contexto léxico, se ejecuta usando ese contexto incluso si es llamada fuera de ese contexto. Las clausuras aparecieron como concepto en los años 60 y fueron llevadas a la práctica por primera vez en un lenguaje que se llama Scheme.

Variables Léxicas Persistentes

En el momento de su creación una subrutina - sea anónima o no - toma los valores de las variables del ámbito en el que se encuentra. El ámbito léxico que engloba a la subrutina en el momento de su creación determina una clausura. Un ejemplo:

lhp@nereida:~/Lperl/src$ cat -n closure2.pl
 1  #!/usr/bin/perl -w
 2  use strict;
 3  my $name = 1000;
 4  {
 5    my $name = $name--;
 6
 7    sub pr {
 8      $name++;
 9      return "closure: $name\n";
10    }
11  }
12
13  print $name,"\n";
14  print pr();
15  print pr();
16  print pr();
cuando se ejecuta produce la siguiente salida:
lhp@nereida:~/Lperl/src$ closure2.pl
999
closure: 1001
closure: 1002
closure: 1003

En condiciones normales Perl liberaría la memoria correspondiente a la variable name de la línea 5 al final de su ámbito. Sin embargo, la subrutina pr que la usa continúa visible y la variable name se conserva mientras la rutina este en uso. La única forma de acceder a la variable name de la línea 5 es a través de la subrutina pr.

Esta es una de las característica de una clausura: subrutinas que recuerdan el estado del entorno en el momento de su creación preservando las variables del ámbito léxico que les rodea, incluso después de la desaparición de dicho ámbito léxico.

Retornar una Subrutina

En el siguiente ejemplo la subrutina tutu recibe un número y retorna una subrutina que multiplica su argumento por dicho número. El programa principal aplica crea varias subrutinas y las aplica a una secuencia de números especificados:

lhp@nereida:~/Lperl/src$ closure3.pl 3 1 2 3 4
Multiplicar por 3: (3 6 9 12)
Multiplicar por -1: (-1 -2 -3 -4)

La subrutina creada dinámicamente recuerda el valor de la variable léxica $n en el momento de su creación.

El bucle de la línea 19 crea diferentes clausuras $t que acceden a diferentes instancias de la variable léxica $n.

lhp@nereida:~/Lperl/src$ cat -n closure3.pl
 1  #!/usr/bin/perl -w
 2  use strict;
 3  use Scalar::Util qw(looks_like_number);
 4
 5  sub tutu {
 6    my $n = shift;
 7
 8    sub {
 9      my $x = shift; die "Se esperaba un numero\n" unless looks_like_number($n);
10      return $x*$n;
11    }
12  }
13
14  ########### main #################################
15  die "Uso:\n$0 num1 num2 num3 ...\n" unless (@ARGV > 1);
16  my $n = shift; die "Se esperaba un numero\n" unless looks_like_number($n);
17
18
19  for my $f ($n, -1) {
20    my $t = tutu($f);
21    my @a = map { $t->($_) } @ARGV;
22    print "Multiplicar por $f: (@a)\n";
23  }



Subsecciones
Casiano Rodríguez León
2009-10-04