List::MoreUtilsのapplyを調べてみた

  • List::MoreUtilは配列操作の便利な関数をまとめたモジュールでそこに apply というサブルーチンがある。docより使い方は以下の通り。
    • つまり第一引数にサブルーチン、残りに配列を渡すとその配列に対してサブルーチンを適用してその結果を返してくれる。mapは配列の中身を変えてしまうがapplyは変えない。
my @list = (1 .. 4);
my @mult = apply { $_ *= 2 } @list;
print "\@list = @list\n";
print "\@mult = @mult\n";
__END__
@list = 1 2 3 4
@mult = 2 4 6 8
  • applyの実装はこんなかんじ
    • プロトタイプ宣言でサブルーチンと配列(&@)が渡ることを宣言。
    • @values に配列をコピー
    • shiftでサブルーチンを$actionに、foreachで配列から一つずつサブルーチンに渡す
    • 暗黙的な変数 $_ が $action サブルーチンの引数になる。
    • wantarrayで返り値の状態を見て値を返す。
sub apply (&@) {
    my $action = shift;
    &$action for my @values = @_;
    wantarray ? @values : $values[-1];
}
  • (自分に分かりやすいよう)書きなおしてみた。納得!
    • キモは上記ではプロトタイプ宣言でサブルーチンを宣言しているところ。引数の外でブロック {} を使うと中身は無名サブルーチンになる。こちらの場合、誤って引数の中にブロックを書いたつもりにしてしまうとそれはハッシュとなるので注意が必要。
use strict;
use warnings;
use Data::Dumper;

my @list = (1 .. 4);
my @mult = apply( sub { $_ *= 2 }, @list);
print "\@list = @list\n";
print "\@mult = @mult\n";

sub apply
{
    my ($action, @values) = @_;
    print "$action @values\n";
    my $d = Dumper $action;
    print "$d";
    print "action=", ref $action, "\n";
    print "values=", ref \@values, "\n";

    &$action foreach (@values);
    wantarray ? @values : $values[-1];
}
__END__
CODE(0x9343ff8) 1 2 3 4
$VAR1 = sub { "DUMMY" };
action=CODE
values=ARRAY
@list = 1 2 3 4
@mult = 2 4 6 8