なんか面白そうだったので自分でもやってみた。
カリー化ってA×B×C×...→Z の関数を A→B×C×...→Z にできれば十分だと思ったので、変換後の引数の数は1つと決めてしまった。そういう意味では再帰的に変換する必要もなかったのだけど、元ネタに揃えて A×B×C×...→Z を A→B→C→...→Zにまで変換するようにした。なので、引数が1個になるまでカリー化を続ける必要があるので、やっぱり引数の数は必要なのだった。
sub curry ($$); sub curry ($$) {
my ($argc, $f) = @_;
$argc <= 1
? sub ($) { goto &$f } # wrap for the right prototype
: sub ($) {
my $arg = shift;
curry ($argc - 1, sub { $f->($arg, @_) });
};
}
sub curried_curry ($); *curried_curry = curry 2 => \&curry;
sub curry2 ($); *curry2 = curried_curry 2;
sub curry3 ($); *curry3 = curried_curry 3;
sub mul3 ($$$) {
my ($a,$b,$c) = @_;
return $a * $b * $c;
}
my $c = curry2 \&mul3;
print $c->(2)(3, 4), "\n";
my $cm = curry3 \&mul3;
my $x = $cm->(2)(3);
print $x->(4), "\n";
curried_curry 辺りが一番書いてて脳汁が出る楽しい部分w プロトタイプは趣味で入れてあるけど、そもそも推奨されてないしやり過ぎ感。と思いつつも、プロトタイプをパースすれば引数の数を渡す必要はないかも?
ちなみにA×B×C×...→Z の関数を(A×B×C×...)×(L×M×...)→Z みたいに見なして A×B×C×...→L×M×...→Z のように処理する機能が元のコードでもあったけど、それは再現していない(型が静的に決められないのでこの実装方針だと難しい)。