Groovy tem um conceito que chama de 'currying'. Aqui está um exemplo de seu wiki:
def divide = { a, b -> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4
Meu entendimento do que está acontecendo aqui é que o argumento da direita divide
está vinculado ao valor 2. Isso parece uma forma de aplicação parcial.
O termo currying geralmente é usado para significar transformar uma função que leva uma série de argumentos em uma função que leva apenas um argumento e retorna outra função. Por exemplo, aqui está o tipo da curry
função em Haskell:
curry :: ((a, b) -> c) -> (a -> (b -> c))
Para as pessoas que não usaram Haskell a
, b
e c
são todos os parâmetros genéricos. curry
recebe uma função com dois argumentos e retorna uma função que recebe a
e retorna uma função de b
para c
. Adicionei um par extra de colchetes ao tipo para deixar isso mais claro.
Eu entendi mal o que está acontecendo no exemplo groovy ou é apenas uma aplicação parcial com o nome errado? Ou, de fato, faz as duas coisas: ou seja, converte-se divide
em uma função ao curry e depois se aplica parcialmente 2
a essa nova função.
fonte
Respostas:
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 deCurriedClosure
. Nesse caso, ele usa o mencionado acimagetUncurriedArguments
para compor a matriz completa de argumentos a serem aplicados: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 novapartial
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 nomeadocurry
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:… 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.fonte
and you die a little inside
Eu acho que é claro que o curry groovy é realmente uma aplicação parcial quando se considera funções com mais de dois argumentos. considerar
sua forma ao curry seria
no entanto, o curry do groovy retornará algo equivalente a (assumindo chamado com 1 argumento x)
que chamará f com o valor de um fixo para x
ou seja, enquanto o curry do groovy pode retornar funções com argumentos N-1, as funções com curry corretamente apenas têm 1 argumento, portanto, o groovy não pode curry com curry
fonte
O Groovy pegou emprestado o nome de seus métodos de curry de várias outras linguagens FP não puras, que também usam nomes semelhantes para aplicação parcial - talvez lamentável por essa funcionalidade centrada em FP. Existem várias implementações de currying "reais" sendo propostas para inclusão no Groovy. Um bom tópico para começar a ler sobre eles está aqui:
http://groovy.markmail.org/thread/c4ycxdzm3ack6xxb
A funcionalidade existente permanecerá de alguma forma e a compatibilidade com versões anteriores será levada em consideração ao fazer uma chamada sobre o nome dos novos métodos, etc. - portanto, não posso dizer nesta fase qual será a nomeação final dos novos / antigos métodos. estar. Provavelmente um comprometimento na nomeação, mas veremos.
Para a maioria dos programadores de OO, a distinção entre os dois termos (currying e aplicação parcial) é discutivelmente amplamente acadêmica; no entanto, quando você estiver acostumado a eles (e quem quiser manter seu código for treinado para ler esse estilo de codificação), a programação no estilo sem ponto ou tácito (que o currying "real" suporta) permite que certos tipos de algoritmos sejam expressos de forma mais compacta e, em alguns casos, de maneira mais elegante. Obviamente, há "beleza nos olhos de quem vê" aqui, mas ter a capacidade de suportar os dois estilos está de acordo com a natureza de Groovy (OO / FP, estática / dinâmica, classes / scripts etc.).
fonte
Dada esta definição encontrada na IBM:
halver
é sua nova função (ou fechamento), que agora requer apenas um parâmetro. A chamadahalver(10)
resultaria em 5.Para isso, transforma uma função com n argumentos em uma função com n-1 argumentos. O mesmo é dito pelo seu exemplo haskell, o que o curry faz.
fonte
rcurry
função (que leva um argumento) em uma função (com agora apenas um argumento). Eu vinculei a função curry com um argumento à minha função base para obter minha função resultante.n - 1
argumentos. Veja o exemplo no final da minha resposta; veja também mais adiante neste artigo para saber mais sobre a distinção que está sendo feita. en.wikipedia.org/wiki/…partial
.