カリー化とアンカリー化

論理学者 Haskell Curry の名前に由来するカリー化は、 同時に複数の引数を取る関数をそれらの引数を連続して取るような関数に本体は同じまま変換することを意味します。 アンカリー化はカリー化の反対です。 次のコードでは、 定義された関数 acker1acker2 はアッカーマン関数を実装しています。 この関数は原始再帰関数でない再帰として有名です:

fun acker1 (m: int, n: int): int = ( if m > 0 then if n > 0 then acker1 (m-1, acker1 (m, n-1)) else acker1 (m-1, 1) else n+1 // end of [if] ) fun acker2 (m: int) (n: int): int = ( if m > 0 then if n > 0 then acker2 (m-1) (acker2 m (n-1)) else acker2 (m-1) 1 else n+1 // end of [if] )

関数 acker2acker1 のカリー化されたバージョンです。 また関数 acker1acker2 のアンカリー化されたバージョンです。 acker2 を整数の値に適用するとクロージャ関数を生成します。 実行時にガベージコレクション (GC) によって回収されないと、 このクロージャ関数はメモリリークを引き起こします。

ML や Haskell のような関数型言語では、 複数引数の関数はカリー化するか、唯一の引数としてタプルを取る関数に変換する必要があります。 そのような言語では、カリー化はしばしば実行時の効率を向上させるので好んで使用されんます。 ATS では複数引数の関数が直接サポートされています。 また複数引数の関数が与えられた時、 その関数のカリー化されたバージョンは元のバージョンより実行時の効率が悪くなることがあります。 これは ATS コンパイラ atsopt のカリー化された関数の取り扱いに起因します。 そのため、ATS においてカリー化の必要性はとても小さいことになります。 一般に説得力のある理由なしに、 カリー化は ATS において推奨されるプログラミングスタイルではありません

この章のコード全体と追加のテストコードは オンライン から入手できます。 (訳注: このコードを atscc でコンパイルする際には -DATS_MEMALLOC_LIBC オプションが必要です。)