Perl高階関数

高階関数とは、関数を引数としたり、関数を返したりするような関数のことなわけだけども、Perlで使う人が多いとは思わない。そもそもsubを関数定義じゃなくてクロージャ生成に使う人って言うのが少ない。だが、そんな人でもPerlにおいては二つクロージャを使う機会がある。それは、sortとmapだ。
sort関数もmap関数も、似たような構文になっている。

sort BLOCK LIST
map BLOCK LIST

間違いやすいのは、BLOCKの後ろにはカンマ(",")がいらないことだ。カンマを書くとBLOCKもLISTの一部と解釈されてしまう。ややこしい。
で、先日のデスマーチであるハッシュリファレンスの配列に対して、いろいろなソートをする必要が出た。本来であれば、こういったものはSQLでORDER BYしてやるのが正しいのだけども、SQLの発行部分をいじくるのが面倒だったので(SQLデバッグはやりたくない)、Perlでソートしてやることになった。ちなみに、データ構造自体は平たくて、

@array = ({id => 1, name => "sawa"}, {id => 2, name => "yuta"}....);

といったような感じになっていた。単にSQLでひいてきた表組みそのままの形になっているのだ。
だが、ソートする規則が常に一定というわけではなく、ある二つの整数変数の値によって決まる。$var1が1で$var2が1だったら、そのハッシュリファレンス中のnameでソートする、$var1が1で$var2が2だったらほげほげで・・・といったイメージだ。でも、常にソートするのだから、ifでケース分けをしてやるというのは面倒だ。っていうか、ソースが汚い。ということで、一つ関数をかませることにした。

sub sort_func{
    $var1 = shift;
    $var2 = shift;
    [
        [
            sub {$a->{id} <=> $b->{id}}
            sub {$a->{name} cmp $b->{name}}
        ],
        [
            sub {$b->{id} <=> $a->{id}}
            sub {$b->{name} cmp $a->{name}}
        ]
    ]->[$var1]->{$var2];
}

で、例えば

my $sort_func = sort_func($var1, $var2);
my @return = sort $sort_func @array;

としてやればいいんだけども、ここで一つ困った。一旦sort_funcの返り値を変数で受け取ってやる必要があるのだ。本来であれば、

sort sort_func($var1, $var2) @array;

というように書きたいのだが、現在のPerlでは書けない(Perl6は不明)。構文エラーと怒られてしまう。で、いろいろと試してみたのだが、出来ないようだ。mapやsortの直後にある関数は、何度もその後ろにあるLISTに対して適用するものであって、決して先に評価するcall by value仕様ではないからだろう。
でも、これが出来ないと結構不便なんだよなあ・・・ということで、ちょっと考えてみた。例えば、次のような関数mysortを定義してやる。

sub mysort{
    my $func = shift;
    sort $func @_;
}
my @return = mysort sort_func($var1, $var2),@array;

こうしてやれば、先に関数が評価されるので何の問題もない・・・が、まあ気持ち悪いといえばそうかもしれない。そもそも、このsortとmapの仕様が気持ち悪いというのがその根底にあるのだけど・・・・