有限リンクトリストのmap

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

listのmapということで,Lmapとしました.Higher-Order Perlでは,transformという名前になっていますが,mapの方が短いので(^^;.これを実行してみると

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

print Dumper Lmap {$_[0]*2} $a;

main::Lmap() called too early to check prototype at list.pl line 32.
$VAR1 = [
          2,
          [
            4,
            [
              6,
              [
                8,
                undef
              ]
            ]
          ]
        ];

use warningsの下では,このように警告がでてしまいます.perldoc perldiagをして当該部分をみてみると

%s() called too early to check prototype
(W prototype) You've called a function that has a prototype before
the parser saw a definition or declaration for it, and Perl could
not check that the call conforms to the prototype. You need to
either add an early prototype declaration for the subroutine in
question, or move the subroutine definition ahead of the call to get
proper prototype checking. Alternatively, if you are certain that
you're calling the function correctly, you may put an ampersand
before the name to avoid the warning. See perlsub.

ざっくり訳すとこんな感じ.

%s() called too early to check prototype
(警告,プロトタイプ) パーサがプロトタイプつきのサブルーチンの定義または宣言を見る前に,それを呼び出しています.ですのでPerlはその呼び出しがプロトタイプに従っているかチェックすることはできません.それよりも前にそのサブルーチンのプロトタイプ宣言を行うか,プロトタイプを適切にチェックできるようにサブルーチンの定義を呼び出しよりも前に移動してください.もしくは,その関数を正しく呼び出していると確信しているならば,サブルーチン名に & をつけて警告を避けてください.perlsub参照.

これを回避するには,& を使う,つまり,

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

とするのが一番簡単ですが,サブルーチンの呼び出しに & をつけるのはPerl4みたいで嫌です.一方,プロトタイプ宣言を行うならば,こんな感じになります.

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

今度は,内部での呼び出しにもしっかりチェックが入って,サブルーチンのリファレンス $f をデリファレンスして,それを { } にいれないといけません.こうしないと

Type of arg 1 to main::Lmap must be block or sub {} (not subroutine entry) at li
st.pl line 34, near ") ) "

というエラー,つまり,変数 $f じゃだめ,きちんとサブルーチンをおきなさいといわれてしまいます.

ということで,プロトタイプ宣言の方がしばりがきついので,ここは妥協して, & をつけて呼び出すことにします.

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

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

print Dumper Lmap {$_[0]*2} $a;

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

MJD先生のHigher-Order Perlではもっと高尚な手段を使ってますが,無限リンクトリストも視野にいれたものなのでまだそれは使いません.