L'implementazione di Groovy in curry
realtà non funziona in nessun momento, anche dietro le quinte. È essenzialmente identico all'applicazione parziale.
Gli curry
, rcurry
e ncurry
metodi restituiscono un CurriedClosure
oggetto che contiene gli argomenti legati. Ha anche un metodo getUncurriedArguments
(nome errato: funzioni di curry, non argomenti) che restituisce la composizione degli argomenti passati ad esso con gli argomenti associati.
Quando viene chiamata una chiusura, alla fine chiama il invokeMethod
metodo diMetaClassImpl
, che controlla esplicitamente se l'oggetto chiamante è un'istanza di CurriedClosure
. In tal caso, utilizza quanto sopra getUncurriedArguments
per comporre l'intera gamma 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 in qualche modo 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 - si è mescolato al curry con un'applicazione parziale. Questo è comprensibile (vedi la risposta di Paul King), anche se un po 'sfortunato; sarà difficile correggerlo senza interrompere la compatibilità all'indietro.
Una soluzione che ho suggerito è quella di sovraccaricare il curry
metodo in modo tale che quando non viene passato alcun argomento faccia un vero curry, e deprecare chiamare il metodo con argomenti a favore di una nuova partial
funzione. Questo potrebbe sembrare un po 'strano , ma massimizzerebbe la retrocompatibilità - poiché non c'è motivo di usare un'applicazione parziale con zero argomenti - evitando la brutta situazione (IMHO) di avere una nuova funzione con un nome diverso per il curry corretto mentre la funzione in realtà named curry
fa qualcosa di diverso e confusamente simile.
Va da sé che il risultato della chiamata curry
è completamente diverso dall'effettivo curry. Se la funzione fosse davvero curry, saresti 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 genera un'eccezione di runtime e muori un po 'dentro.