Groovys Implementierung von curry
curry nicht einmal hinter den Kulissen. Es ist im Wesentlichen identisch mit der Teilanwendung.
Die Methoden curry
, rcurry
und geben ein Objekt zurück , das die gebundenen Argumente enthält. Es gibt auch eine Methode (falsch benannt - Sie verwenden Curry-Funktionen, keine Argumente), die die Zusammensetzung der Argumente zurückgibt, die mit den gebundenen Argumenten an sie übergeben wurden.ncurry
CurriedClosure
getUncurriedArguments
Wenn ein Closure aufgerufen wird, ruft es letztendlich die invokeMethod
Methode von aufMetaClassImpl
, die explizit prüft, ob das aufrufende Objekt eine Instanz von ist CurriedClosure
. In diesem Fall werden die oben genannten getUncurriedArguments
Informationen verwendet , um die gesamte Anzahl der anzuwendenden Argumente zusammenzustellen:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Aufgrund der verwirrenden und etwas inkonsistenten obigen Nomenklatur vermute ich, dass derjenige, der dies geschrieben hat, ein gutes konzeptuelles Verständnis hat, aber vielleicht ein wenig überstürzt war und - wie viele kluge Leute - das Currying mit einer teilweisen Anwendung in Konflikt brachte. Dies ist verständlich (siehe Antwort von Paul King), wenn auch etwas unglücklich; Es wird schwierig sein, dies zu korrigieren, ohne die Abwärtskompatibilität zu beeinträchtigen.
Eine Lösung, die ich vorgeschlagen habe, besteht darin, die curry
Methode so zu überladen , dass sie, wenn keine Argumente übergeben werden, tatsächlich ausgeführt wird , und den Aufruf der Methode mit Argumenten zugunsten einer neuen partial
Funktion nicht mehr zu empfehlen . Dies mag ein wenig seltsam erscheinen , würde jedoch die Abwärtskompatibilität maximieren, da es keinen Grund gibt, eine Teilanwendung mit Nullargumenten zu verwenden, und gleichzeitig die (IMHO) hässlichere Situation vermeiden, eine neue, anders benannte Funktion für das ordnungsgemäße Aufrufen zu haben, während die Funktion tatsächlich ausgeführt wird named curry
macht etwas anderes und verwirrend ähnliches.
Es versteht sich von selbst, dass sich das Ergebnis eines Anrufs curry
völlig vom tatsächlichen Currying unterscheidet. Wenn die Funktion wirklich funktioniert, können Sie schreiben:
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
... und es würde funktionieren, denn addCurried
sollte funktionieren wie { x -> { y -> x + y } }
. Stattdessen wird eine Laufzeitausnahme ausgelöst und Sie sterben ein wenig im Inneren.