Реалізація Groovy curryнасправді не викликає куріння, навіть за кулісами. Він по суті ідентичний частковому застосуванню.
В curry, rcurryі ncurryметоди повертають CurriedClosureоб'єкт , який утримує пов'язані аргументи. Він також має метод getUncurriedArguments(неправильно названий - ви curry функції, а не аргументи), який повертає композицію переданих йому аргументів зв'язаними аргументами.
Коли укупорочное викликається, в кінцевому підсумку це викликає в 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);
}
Виходячи із заплутаної та дещо непослідовної номенклатури вище, я підозрюю, що кожен, хто це написав, має хороше концептуальне розуміння, але, можливо, трохи поспішав і - як багато розумних людей - плутав каррі з частковим застосуванням. Це зрозуміло (див. Відповідь Пола Кінга), якщо трохи прикро; це буде важко виправити, не порушуючи зворотної сумісності.
Я запропонував одне рішення - перевантажити curryметод таким чином, що коли аргументи не передаються, він робить справжній currying, і знецінює виклик методу аргументами на користь нової partialфункції. Це може здатися трохи дивним , але це дозволило б максимально збільшити зворотну сумісність - оскільки немає причин використовувати часткове застосування з нульовими аргументами - уникаючи при цьому (IMHO) потворнішої ситуації мати нову, інакше названу функцію для правильного currying, а функція насправді названий 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 } }. Натомість це кидає виняток із виконання, і ти трохи помреш всередині.