Groovyの実装 curry
、舞台裏であっても実際にはどの時点でもカレーしません。これは、部分的なアプリケーションと本質的に同じです。
curry
、rcurry
およびncurry
方法は返すCurriedClosure
オブジェクトをバインドされた引数を保持しています。またgetUncurriedArguments
、バインドされた引数とともに渡された引数の構成を返すメソッド(名前は間違っています-引数ではなく関数です)があります。
クロージャが呼び出されると、最終的にのinvokeMethod
メソッドをMetaClassImpl
呼び出し、呼び出し元のオブジェクトがのインスタンスであるかどうかを明示的に確認しますCurriedClosure
。その場合、前述の方法getUncurriedArguments
を使用して、適用する引数の完全な配列を作成します。
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
上記の混乱したやや一貫性のない命名法に基づいて、私はこれを書いた人は誰でも概念的な理解を持っていると思うが、多分少し急ぎ、おそらく多くの賢い人々のようにカリー化を部分適用と混同した。少し不幸な場合、これは理解できます(ポールキングの答えを参照)。後方互換性を損なうことなくこれを修正することは困難です。
私が提案した解決策の1つはcurry
、引数が渡されないときに実際にカリー化するようにメソッドをオーバーロードし、新しいpartial
関数を優先して引数を使用してメソッドを呼び出すことを非推奨にすることです。これは少し奇妙に思えるかもしれませんが、後方互換性を最大化するでしょう(引数なしで部分的なアプリケーションを使用する理由がないためです)。 named curry
は何か違うもので、紛らわしいほど似ています。
curry
言うまでもなく、呼び出しの結果は実際のカレーとはまったく異なります。関数が本当にカリー化されている場合、次のように書くことができます。
def add = { x, y -> x + y }
def addCurried = add.curry() // should work like { x -> { y -> x + y } }
def add1 = addCurried(1) // should work like { y -> 1 + y }
assert add1(1) == 2
…そしてのように動作するaddCurried
はずなので、動作し{ x -> { y -> x + y } }
ます。代わりに、実行時例外がスローされ、内部で少し死にます。