L'implementazione di Groovy di curry
in realtà non curry in nessun punto, anche dietro le quinte. È essenzialmente identico all'applicazione parziale.
I metodi curry
, rcurry
e ncurry
return un oggetto CurriedClosure
che contiene gli argomenti associati. Ha anche un metodo getUncurriedArguments
(misnamed-you curry functions, non arguments) che restituisce la composizione degli argomenti passati ad esso con gli argomenti associati.
Quando viene chiamata una chiusura, alla fine chiama invokeMethod
metodo di MetaClassImpl
, che verifica esplicitamente se l'oggetto chiamante è un'istanza di CurriedClosure
. In tal caso, utilizza il summenzionato getUncurriedArguments
per comporre l'array completo di argomenti da applicare:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Sulla base della nomenclatura confusa e alquanto incoerente di cui sopra, sospetto che chiunque abbia scritto questo abbia una buona comprensione concettuale, ma forse è stato un po 'affrettato e, come molte persone intelligenti, ha confuso il curriculum con un'applicazione parziale. Questo è comprensibile (vedi la risposta di Paul King), se un po 'sfortunato; sarà difficile correggerlo senza rompere la compatibilità con le versioni precedenti.
Una soluzione che ho suggerito è di sovraccaricare il metodo curry
in modo tale che quando non viene passato alcun argomento lo fa real currying e deprecate chiamando il metodo con argomenti in favore di una nuova funzione partial
. Questo potrebbe sembrare un po 'strano , ma ottimizzerebbe la compatibilità con le versioni precedenti, dal momento che non c'è motivo di utilizzare un'applicazione parziale con argomenti zero- evitando allo stesso tempo la situazione più brutta (IMHO) di avere una nuova funzione con nomi diversi per una corretta elaborazione mentre la funzione effettivamente chiamata curry
fa qualcosa di diverso e di confusione simile.
Inutile dire che il risultato della chiamata di curry
è completamente diverso da quello attuale. Se davvero curried la funzione, si sarebbe in grado di scrivere:
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
... e funzionerebbe, perché addCurried
dovrebbe funzionare come { x -> { y -> x + y } }
. Invece lancia un'eccezione di runtime e muori un po 'dentro.