A implementação de Groovy na curry
verdade não se curry a qualquer momento, mesmo nos bastidores. É essencialmente idêntico à aplicação parcial.
Os métodos curry
, rcurry
e retornam um objeto que contém os argumentos vinculados. Ele também possui um método (denominado incorretamente - funções curry, não argumentos) que retorna a composição dos argumentos passados a ele com os argumentos encadernados.ncurry
CurriedClosure
getUncurriedArguments
Quando um fechamento é chamado, ele finalmente chama o invokeMethod
método deMetaClassImpl
, que verifica explicitamente se o objeto de chamada é uma instância de CurriedClosure
. Nesse caso, ele usa o mencionado acima getUncurriedArguments
para compor a matriz completa de argumentos a serem aplicados:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Com base na nomenclatura confusa e um tanto inconsistente acima, desconfio que quem escreveu isso tenha um bom entendimento conceitual, mas talvez tenha sido um pouco apressado e - como muitas pessoas inteligentes - conflitou com a aplicação parcial. Isso é compreensível (veja a resposta de Paul King), se um pouco infeliz; será difícil corrigir isso sem quebrar a compatibilidade com versões anteriores.
Uma solução que sugeri é sobrecarregar o curry
método, de modo que, quando nenhum argumento é passado, ele efetua um curry real e descontinua a chamada do método com argumentos a favor de uma nova partial
função. Isso pode parecer um pouco estranho , mas maximizaria a compatibilidade com versões anteriores - já que não há razão para usar aplicativos parciais com zero argumentos - evitando a situação mais feia (IMHO) de ter uma nova função com nome diferente para currying adequado enquanto a função realmente nomeado curry
faz algo diferente e similarmente confuso.
Escusado será dizer que o resultado da chamada curry
é completamente diferente do curry real. Se realmente cursou a função, você seria capaz de escrever:
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 funcionaria, porque addCurried
deveria funcionar como { x -> { y -> x + y } }
. Em vez disso, lança uma exceção de tempo de execução e você morre um pouco por dentro.