2012年9月8日土曜日

小ネタ: Perl の警告: Deep recursion on subroutine ...

Perl では再帰呼び出しのネストが深いと警告してくれる機能がある。定石的に use strict; use warnings; していれば有効になっている。

use warnings;
sub dfs {
    if($_[0] < 101) { dfs($_[0]+1); }
}
dfs(0);
Deep recursion on subroutine "main::dfs" at ... line 3.

perldiag には "unless you're writing strange benchmark programs, in which case it indicates something else." などと書いてあったりするのだが、閾値が 100 であるためちょっと大きめのグラフに対して再帰で DFS かけたりしたら余裕で突破したりするのである。警告を抑制したい場合、Perl の警告はカテゴリ分けされているため再帰に関する警告だけオフにしてやればいい。

use warnings;
no warnings 'recursion';
sub dfs {
    if($_[0] < 101) { dfs($_[0]+1); }
}
dfs(0);

が、これだと全体で警告がオフになってしまう。Perl の警告制御は lexical scope である。これは限定した部分で警告をオン・オフできるということだが、

use warnings;
sub dfs {
    if($_[0] < 101) {
        no warnings 'recursion';
        dfs($_[0]+1);
    } # End of the effect of no warnings
}
dfs(0);

もう一つ、dynamic scope ではない、ということも意味している。つまり、以下では警告は抑制されない。

use warnings;
sub dfs {
    if($_[0] < 101) {
        dfs($_[0]+1);
    }
}
no warnings 'recursion';
dfs(0);

実際に deep recursion が発生するのは dfs(0); の実行中じゃないかと思ってしまうのだが、字面上(lexical)は 4 行目の dfs 呼び出しで発生するからだ。

0 件のコメント:

コメントを投稿