Un generador es una rutina que provee una forma de iterar sobre una estructura de datos. Habitualmente no toda la estructura reside en memoria y el generador la recorre realizando las operaciones necesarias para la construcción del siguiente elemento.
~/Lperl/src$ perl allsubsets.pl A B C D | perl -ne 'printf "%2d:%4b %s",$k,$k,$_; $k++' 0: 0 () 1: 1 (A) 2: 10 (B) 3: 11 (A, B) 4: 100 (C) 5: 101 (A, C) 6: 110 (B, C) 7: 111 (A, B, C) 8:1000 (D) 9:1001 (A, D) 10:1010 (B, D) 11:1011 (A, B, D) 12:1100 (C, D) 13:1101 (A, C, D) 14:1110 (B, C, D) 15:1111 (A, B, C, D)
pp2@nereida:~/src/perl/coro$ cat -n allsubsetsco.pl
1 #!/usr/bin/perl -w
2 use strict;
3 use Coro::State;
4
5 sub create_generator {
6 my @set = @_;
7 my $powern = 1 << @set;
8 my $n = -1;
9 my @RESULT;
10
11 my $caller = Coro::State->new;
12 # Create coroutine
13 my $coroutine;
14 $coroutine = Coro::State->new( sub {
15 while () {
16 $n = -1 if $n == $powern;
17 $n++;
18 @RESULT = map { $n & (1 << $_)? ($set[$_]) : () } 0..$#set;
19 $coroutine->transfer($caller);
20 }
21 } );
22
23 return sub {
24 $caller->transfer($coroutine);
25 return @RESULT;
26 };
27 };
28
29 sub traverse {
30 my $t = shift;
31 my $length = shift;
32 my @q;
33 do {
34 @q = $t->();
35
36 local $" = ', ';
37 print "(@q)";
38 print "\n";
39
40 } while (@q != $length);
41 }
42
43 my $t = create_generator(qw{a b c d});
44 my $s = create_generator(qw{0 1 2});
45
46 traverse($t, 4);
47 print "\n**********************\n";
48 traverse($s, 3);
pp2@nereida:~/src/perl/coro$ allsubsetsco.pl | cat -n
1 ()
2 (a)
3 (b)
4 (a, b)
5 (c)
6 (a, c)
7 (b, c)
8 (a, b, c)
9 (d)
10 (a, d)
11 (b, d)
12 (a, b, d)
13 (c, d)
14 (a, c, d)
15 (b, c, d)
16 (a, b, c, d)
17
18 **********************
19 ()
20 (0)
21 (1)
22 (0, 1)
23 (2)
24 (0, 2)
25 (1, 2)
26 (0, 1, 2)
