четверг, 29 октября 2009 г.

each и return - опасное соседство


keys %foo;
while (my ($k, $v) = each %foo) {
...
return ...;
}

Для вышеприведенного кода, если while вызывается более чем один раз за время существования хеша %foo, не следует забывать о сбросе итератора each при помощи keys.

Я вот забыл, так как практически не использую each, и потратил время на поиски причины, почему код выдает неверный результат. Хорошо, что сразу написал тест и увидел, что есть ошибка.

пятница, 23 октября 2009 г.

Прототипы и аргументы из списка

Вызывая подпрограмму

sub foo($$$$) { }

Так хочется вместо, например,

foo(1, $foo{1}, $foo{3}, $foo{5});

Написать

foo(1, @foo{qw(1 3 5)});

Но нельзя, так как Perl ругается, что недостаточно аргументов. :-(

четверг, 15 октября 2009 г.

PSGI и SpeedyCGI

Благодаря Алексею Капранову узнал о появлении PSGI/Plack. PSGI - cпецификация интерфейса между Perl web приложениями и web серверами. Plack - реализация.

Интересно, а SpeedyCGI (PersistentPerl) часто используют для HTTP? Для тех кто не знает: SpeedyCGI можно использовать не только для HTTP при помощи mod_speedycgi из под Apache, а как полноценный PersistentPerl для любых Perl приложений.

четверг, 1 октября 2009 г.

Reduced map

Как известно в Perl 6 имеются гипер- и редакшноператоры
(заметка о них http://laziness-impatience-hubris.blogspot.com/2009/01/perl6.html).

Но что же делать в Perl 5?

Для замены редакшноператоров можно воспользоваться подпрограммой reduce из модуля List::Util или
воспользоваться "reduced map" (rmap) из нижеприведенного модуля (List::Rmap).
Замена же гипероператоров осуществляется при помощи "hyper map" (hmap) того же модуля.

Рассмотрим примеры.

use strict;
use warnings;

use List::Rmap qw(reduce rmap hmap);

my @a = (1, 2, 3);
my @b = (4, 5, 6);

print reduce { $a + $b } @a;
# Бyдет напечатано 6
# Это в Perl6 эквивалентно [+] @x
print "\n";

# reduced map
print join " ", rmap { $a + $b } @a;
# Бyдет напечатано 1 3 6
# Это в Perl6 эквивалентно [\+] @x
print "\n";

# hyper map
print join " ", hmap { $a + $b } @a, @b;
# Бyдет напечатано 5 7 9
# Это в Perl6 эквивалентно @x >>+<< @y


А вот содержимое вышеупомянутого модуля List::Rmap:

# Reduced map

package List::Rmap;

use strict;
use warnings;

no strict qw(refs);

use Exporter;
our @EXPORT_OK = qw(reduce rmap hmap);


sub import {

# Avoid "Name "..." used only once" warnings for $a and $b.
my $caller = caller;
local *{"${caller}::a"};
local *{"${caller}::b"};

goto &Exporter::import
}



sub reduce (&@) {
my $code = shift;

my $caller = caller;
local *{"${caller}::a"} = \ my $a;
local *{"${caller}::b"} = \ my $b;

$a = shift;
foreach (@_) {
$b = $_;
$a = &{$code}();
}

return $a;
}



sub rmap (&@) {
my $code = shift;

my $caller = caller;
local *{"${caller}::a"} = \ my $a;
local *{"${caller}::b"} = \ my $b;

my @r = ($a = shift);
foreach (@_) {
$b = $_;
push @r, $a = &{$code}();
}

return @r;
}



sub hmap (&\@\@) {
my $code = shift;
my ($ra, $rb) = @_;

@$ra == @$rb or die "Different length of lists.";

my $caller = caller;
local *{"${caller}::a"} = \ my $a;
local *{"${caller}::b"} = \ my $b;

my @r = ();
foreach ($[ .. $#$ra) {
$a = $$ra[$_];
$b = $$rb[$_];
push @r, &{$code}();
}

return @r;
}


1;