La implementación de Groovy en curry
realidad no curry en ningún momento, incluso detrás de escena. Es esencialmente idéntico a la aplicación parcial.
Los curry
, rcurry
y ncurry
métodos devuelven un CurriedClosure
objeto que contiene los argumentos encuadernados. También tiene un método getUncurriedArguments
(mal nombrado: funciones de curry, no argumentos) que devuelve la composición de los argumentos que se le pasan con los argumentos enlazados.
Cuando se llama a un cierre, finalmente llama al invokeMethod
método deMetaClassImpl
, que verifica explícitamente si el objeto que llama es una instancia de CurriedClosure
. Si es así, utiliza lo mencionado anteriormente getUncurriedArguments
para componer el conjunto completo de argumentos a aplicar:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Basado en la confusa y algo inconsistente nomenclatura anterior, sospecho que quien escribió esto tiene una buena comprensión conceptual, pero tal vez se apresuró un poco y, como muchas personas inteligentes, combinó el curry con una aplicación parcial. Esto es comprensible (ver la respuesta de Paul King), aunque un poco desafortunado; Será difícil corregir esto sin romper la compatibilidad con versiones anteriores.
Una solución que he sugerido es sobrecargar el curry
método de tal manera que cuando no se pasan argumentos, esto realmente hace curry, y desaprobar llamar al método con argumentos a favor de una nueva partial
función. Esto puede parecer un poco extraño , pero maximizaría la compatibilidad con versiones anteriores, ya que no hay razón para usar una aplicación parcial con cero argumentos, al tiempo que evita la situación más fea (en mi humilde opinión) de tener una nueva función con un nombre diferente para un currículum adecuado mientras la función realmente llamadocurry
hace algo diferente y confusamente similar.
No hace falta decir que el resultado de llamar curry
es completamente diferente del curry real. Si realmente curry la función, podría escribir:
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
... y funcionaría, porque addCurried
debería funcionar así { x -> { y -> x + y } }
. En cambio, arroja una excepción de tiempo de ejecución y mueres un poco por dentro.