Perlでlet rec

Perlには、let recにあたるものが無い。ちょっと語弊があるかもしれないけれども、構文としては無い。Perl再帰をする場合のことを考えてみると、

sub fact{
    $_[0] < 1 ? 1 : $_[0] * fact($_[0] - 1);
}

と書けるけれども、あくまでこれはSchemeで言うところのdefineであって、let-recではない。つまり、スコープがグローバルになってしまうのだ。出来れば名前空間をなるべく汚したくないという要請により、このようなコードは書きたくない。
とはいえ、無名関数を作るsubでは、自分自身の名前を取得することは出来ないし、subによる関数宣言ではどこに書いてもグローバルなスコープになってしまう。
では、次のコードはどうだろうか。

my $fact = sub{ $_[0] < 1 ? 1 : $_[0] * &$fact($_[0] - 1)};

実は、これはuse strictで書けない。なぜなら、左辺で宣言している変数が右辺で使われているためだ。なので、次のように書く必要がある。

my $fact;
$fact = sub { $_[0] < 1 ? 1 : $_[0] * &$fact($_[0] - 1)};

これだと、宣言と同時に代入できないのでよろしくない。
ということで、

my $fact = sub {$_[1] < 1 ? 1 : $_[1] * &$_[0]($_[1] - 1)};
&$fact($fact, 6);

というように、第一引数に自分自身を入れてやればいいんじゃないか。これで、let recのような意味が可能になる。で、なんかよくわからないんだけれども、kosak氏はここからYオペレータを書き出した。使い方は以下の通り。

my $fact = &$y(sub {
    my $fact = shift;
    $_[0] < 1 : 1 ? $_[0] * &$fact($[0] - 1)
});

どうやったらこんなYオペレータが書けるかは自分で調べてみてくださいな、と。まあPerlには型が無いから書きやすいとは思うけど。

Special Thanks: kosak氏