Lmap/filter の引数に $_ を

Lmap/filterの第一引数には sub を省略した無名サブルーチンを使えますが,そのサブルーチンの引数は一個で,$_[0] を使います.一方,Perlの組み込みのmap/grepでは,デフォルトの $_ を使います.そこで,Lmap/filterでも同じように $_ に変更してみます.

sub Lmap(&$){
    my ($f, $l) = @_;
    my $trans =sub{
        local $_=shift;
	$f->();
    };
    return unless $l;
    node ($trans->(head($l)), &Lmap($f, tail($l)) );
}

sub filter(&$){
    my ($f,$l) = @_;
    my $checker = sub{
	local $_ = shift;
	$f->();
    };
    return unless $l;
    my $temp=head($l);
    if ($checker->($temp)){
	node($temp, &filter($f,tail($l)));
    }else{
	&filter($f,tail($l));
    }
}

localで $_ の値をサブルーチンの中でだけ引数にして,それをLmap/filterの第一引数の中の $_ として使うというトリックです.$_ はグローバル変数ですが,この処理で局所化できます.

ここでわかるのは「無名サブルーチンの中は評価されない」というか「実際に呼び出されたときに評価される」という遅延評価っぽいことが起こることです.Lmap/filterの引数として使われた段階で $_ が評価されてしまったら当然困ってしまいますので,そういうことはないということです.

この変更で

my $a=[ 1, [2, [ 3, [4,undef ] ] ] ];

print Dumper (Lmap {$_ * 2} $a);
print Dumper (filter {$_ % 2} $a);

$VAR1 = [
          2,
          [
            4,
            [
              6,
              [
                8,
                undef
              ]
            ]
          ]
        ];
$VAR1 = [
          1,
          [
            3,
            undef
          ]
        ];

と出てくるようになりました.