Реалізація 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 } }
. Натомість це кидає виняток із виконання, і ти трохи помреш всередині.