Implementacja curry
Groovy'ego nie curry w żadnym momencie, nawet za kulisami. Jest zasadniczo identyczny z częściowym zastosowaniem.
Te curry
, rcurry
oraz ncurry
metody zwracają CurriedClosure
obiekt , który przechowuje związanego argumenty. Ma także metodę getUncurriedArguments
(źle nazwaną - curry funkcje, a nie argumenty), która zwraca skład argumentów przekazanych mu wraz z powiązanymi argumentami.
Kiedy zamknięcie jest wywoływana, to ostatecznie nazywa się invokeMethod
metodęMetaClassImpl
, która jawnie sprawdza, czy obiekt wywołujący jest instancją CurriedClosure
. Jeśli tak, wykorzystuje powyższe getUncurriedArguments
do ułożenia pełnej tablicy argumentów do zastosowania:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Opierając się na mylącym i nieco niekonsekwentnym nazewnictwie powyżej, podejrzewam, że ktokolwiek to napisał, ma dobre zrozumienie pojęciowe, ale być może był nieco pochopny i - jak wielu inteligentnych ludzi - splątał curry z częściowym zastosowaniem. Jest to zrozumiałe (patrz odpowiedź Paula Kinga), jeśli trochę niefortunne; trudno będzie to naprawić bez naruszenia wstecznej kompatybilności.
Jednym z rozwiązań, które zasugerowałem, jest przeciążenie curry
metody w taki sposób, że gdy nie zostaną przekazane żadne argumenty, powoduje ona prawdziwe curry i przestaje być wywoływaniem metody z argumentami na korzyść nowej partial
funkcji. Może to wydawać się trochę dziwne , ale maksymalizuje zgodność wsteczną - ponieważ nie ma powodu, aby używać częściowej aplikacji z zerowymi argumentami - unikając przy tym brzydszej sytuacji (IMHO) posiadania nowej, różnie nazwanej funkcji do właściwego curry, podczas gdy funkcja faktycznie nazwany curry
robi coś innego i myląco podobnego.
Jest curry
rzeczą oczywistą , że wynik wywołania jest zupełnie inny niż faktyczne curry. Jeśli funkcja naprawdę curry tę funkcję, możesz napisać:
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
… I to by działało, bo addCurried
powinno działać jak { x -> { y -> x + y } }
. Zamiast tego generuje wyjątek czasu wykonywania i umierasz trochę w środku.