Eu já vi referências a funções ao curry em vários artigos e blogs, mas não consigo encontrar uma boa explicação (ou pelo menos uma que faça sentido!)
653
Eu já vi referências a funções ao curry em vários artigos e blogs, mas não consigo encontrar uma boa explicação (ou pelo menos uma que faça sentido!)
curry
euncurry
de Haskell. O importante aqui é que esses isomorfismos são corrigidos previamente e, portanto, "incorporados" à linguagem.add x y = x+y
(curry) é diferenteadd (x, y)=x+y
(uncurried)Respostas:
Currying é quando você divide uma função que leva vários argumentos em uma série de funções, cada uma tendo apenas um argumento. Aqui está um exemplo em JavaScript:
Esta é uma função que recebe dois argumentos, aeb, e retorna sua soma. Vamos agora curry esta função:
Esta é uma função que recebe um argumento, ae retorna uma função que recebe outro argumento, b, e essa função retorna sua soma.
A primeira instrução retorna 7, como a instrução add (3, 4). A segunda instrução define uma nova função chamada add3 que adicionará 3 ao seu argumento. É o que algumas pessoas podem chamar de fechamento. A terceira instrução usa a operação add3 para adicionar 3 a 4, produzindo novamente 7 como resultado.
fonte
[1, 2, 3, 4, 5]
que deseja multiplicar por um número arbitrário. Em Haskell, eu posso escrevermap (* 5) [1, 2, 3, 4, 5]
para multiplicar a lista inteira5
e, assim, gerar a lista[5, 10, 15, 20, 25]
.map
deve ser uma função que requer apenas 1 argumento - um elemento da lista. A multiplicação - como conceito matemático - é uma operação binária; são necessários 2 argumentos. No entanto, em Haskell*
é uma função ao curry, semelhante à segunda versãoadd
desta resposta. O resultado de(* 5)
é uma função que pega um único argumento e o multiplica por 5, e que nos permite usá-lo com o mapa.Em uma álgebra de funções, lidar com funções que recebem vários argumentos (ou um argumento equivalente que é uma N-tupla) é um tanto deselegante - mas, como Moses Schönfinkel (e, independentemente, Haskell Curry) provou, não é necessário: tudo o que você precisa. necessidade são funções que levam um argumento.
Então, como você lida com algo que naturalmente expressa como, digamos
f(x,y)
,? Bem, você considera isso como equivalente af(x)(y)
-f(x)
, chame-og
, é uma função e aplica essa função ay
. Em outras palavras, você só possui funções que usam um argumento - mas algumas dessas funções retornam outras funções (que também usam um argumento ;-).Como de costume, a wikipedia tem uma boa entrada resumida sobre isso, com muitos indicadores úteis (provavelmente incluindo os que falam sobre seus idiomas favoritos ;-), além de um tratamento matemático um pouco mais rigoroso.
fonte
div :: Integral a => a -> a -> a
- observe essas múltiplas setas? "Mapear a para a função mapear de a para" é uma leitura ;-). Você pode usar um argumento de tupla (único) para odiv
& c, mas isso seria realmente anti-idiomático em Haskell.Aqui está um exemplo concreto:
Suponha que você tenha uma função que calcula a força gravitacional que atua sobre um objeto. Se você não conhece a fórmula, pode encontrá-la aqui . Esta função aceita os três parâmetros necessários como argumentos.
Agora, estando na Terra, você só deseja calcular forças para objetos neste planeta. Em uma linguagem funcional, você pode passar a massa da Terra para a função e depois avaliar parcialmente. O que você recuperaria é outra função que usa apenas dois argumentos e calcula a força gravitacional dos objetos na Terra. Isso é chamado de curry.
fonte
O curry é uma transformação que pode ser aplicada às funções para permitir que elas tomem um argumento a menos do que anteriormente.
Por exemplo, em F #, você pode definir uma função assim: -
Aqui a função f pega os parâmetros x, ye z e os soma juntos para que: -
Retorna 6.
De nossa definição, podemos, portanto, definir a função curry para f: -
Onde 'fun x -> fx' é uma função lambda equivalente a x => f (x) em C #. Esta função insere a função que você deseja curry e retorna uma função que recebe um único argumento e retorna a função especificada com o primeiro argumento definido no argumento de entrada.
Usando nosso exemplo anterior, podemos obter um curry de f assim: -
Podemos então fazer o seguinte: -
O que nos fornece uma função f1 que é equivalente a f1 yz = 1 + y + z. Isso significa que podemos fazer o seguinte: -
O que retorna 6.
Este processo é frequentemente confundido com 'aplicação parcial da função', que pode ser definida assim:
Embora possamos estendê-lo a mais de um parâmetro, ou seja: -
Um aplicativo parcial pega a função e o (s) parâmetro (s) e retorna uma função que requer um ou mais parâmetros a menos, e como os dois exemplos anteriores mostram é implementado diretamente na definição da função F # padrão, para que pudéssemos obter o resultado anterior assim: -
O que retornará um resultado de 6.
Em conclusão:-
A diferença entre aplicação de função de curry e parcial é que: -
A currying pega uma função e fornece uma nova função, aceitando um único argumento e retornando a função especificada com seu primeiro argumento definido para esse argumento. Isso nos permite representar funções com vários parâmetros como uma série de funções de argumento único . Exemplo:-
O aplicativo de função parcial é mais direto - ele pega uma função e um ou mais argumentos e retorna uma função com os primeiros n argumentos definidos para os n argumentos especificados. Exemplo:-
fonte
Pode ser uma maneira de usar funções para criar outras funções.
Em javascript:
Nos permitiria chamá-lo assim:
Quando isso é executado, o
10
é passado comox
;o que significa que retornamos esta função:
Então, quando você liga
você está realmente ligando:
Então, se você fizer isso:
é o mesmo que:
Portanto, nosso
addTen()
sempre adiciona dez ao que quer que seja transmitido. Podemos fazer funções semelhantes da mesma maneira:Agora, a pergunta óbvia de acompanhamento é por que diabos você gostaria de fazer isso? Ele transforma o que era uma operação ansiosa
x + y
em uma que pode ser percorrida preguiçosamente, o que significa que podemos fazer pelo menos duas coisas: 1. operações caras em cache; 2. obter abstrações no paradigma funcional.Imagine nossa função ao curry parecida com esta:
Poderíamos chamar essa função uma vez e depois passar o resultado a ser usado em muitos lugares, o que significa que só fazemos o material computacionalmente caro uma vez:
Podemos obter abstrações de maneira semelhante.
fonte
Uma função ao curry é uma função de vários argumentos reescritos, de forma que aceita o primeiro argumento e retorna uma função que aceita o segundo argumento e assim por diante. Isso permite que funções de vários argumentos tenham alguns de seus argumentos iniciais parcialmente aplicados.
fonte
map
uma funçãof
em uma lista de listas,xss
poderá fazê-lomap (map f) xss
.Aqui está um exemplo de brinquedo em Python:
(Basta usar a concatenação via + para evitar distrações para programadores que não são Python.)
Edição para adicionar:
Veja http://docs.python.org/library/functools.html?highlight=partial#functools.partial , que também mostra a distinção parcial de objeto versus função na maneira como o Python implementa isso.
fonte
Currying está traduzindo uma função de callable
f(a, b, c)
para callable asf(a)(b)(c)
.Caso contrário, o curry é quando você divide uma função que leva vários argumentos em uma série de funções que fazem parte dos argumentos.
Literalmente, currying é uma transformação de funções: de uma maneira de chamar para outra. Em JavaScript, geralmente criamos um wrapper para manter a função original.
O curry não chama uma função. Apenas o transforma.
Vamos criar a função curry que executa o curry para funções de dois argumentos. Em outras palavras,
curry(f)
para dois argumentos of(a, b)
traduz emf(a)(b)
Como você pode ver, a implementação é uma série de wrappers.
curry(func)
é um invólucrofunction(a)
.sum(1)
, o argumento é salvo no Ambiente Lexical e um novo wrapper é retornadofunction(b)
.sum(1)(2)
, finalmente, chamafunction(b)
fornecendo 2, e passa a chamada para a soma multi-argumento original.fonte
Se você entende
partial
que está no meio do caminho. A idéia departial
é aplicar previamente argumentos a uma função e devolver uma nova função que deseja apenas os argumentos restantes. Quando essa nova função é chamada, ela inclui os argumentos pré-carregados, juntamente com os argumentos que foram fornecidos a ela.Em Clojure
+
é uma função, mas para esclarecer as coisas:Você pode estar ciente de que a
inc
função simplesmente adiciona 1 a qualquer número que seja passado.Vamos construí-lo usando
partial
:Aqui retornamos outra função que carregou 1 no primeiro argumento de
add
. Comoadd
leva dois argumentos, a novainc
função deseja apenas ob
argumento - não 2 argumentos como antes, pois 1 já foi parcialmente aplicado. Assim,partial
é uma ferramenta a partir da qual criar novas funções com os valores padrão pré-fornecidos. É por isso que, em uma linguagem funcional, as funções geralmente ordenam argumentos de geral para específico. Isso facilita a reutilização de tais funções a partir das quais construir outras funções.Agora imagine se a linguagem fosse inteligente o suficiente para entender introspectivamente que
add
desejavam dois argumentos. Quando passamos para um argumento, em vez de recusar, e se a função aplicou parcialmente o argumento, passamos em nosso nome, entendendo que provavelmente pretendíamos fornecer o outro argumento posteriormente? Poderíamos então definirinc
sem usar explicitamentepartial
.É assim que alguns idiomas se comportam. É excepcionalmente útil quando se deseja compor funções em transformações maiores. Isso levaria um a transdutores.
fonte
Encontrei este artigo e o artigo que ele faz referência útil para entender melhor o curry: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
Como os outros mencionados, é apenas uma maneira de ter uma função de um parâmetro.
Isso é útil porque você não precisa assumir quantos parâmetros serão passados; portanto, você não precisa de 2, 3 e 4 funções de parâmetro.
fonte
Como todas as outras respostas, o curry ajuda a criar funções parcialmente aplicadas. Javascript não fornece suporte nativo para currying automático. Portanto, os exemplos fornecidos acima podem não ajudar na codificação prática. Há um exemplo excelente no código de vida (que basicamente compila com js) http://livescript.net/
No exemplo acima, quando você forneceu menos argumentos, o livescript gera uma nova função ao curry para você (duplo)
fonte
O Curry pode simplificar seu código. Esse é um dos principais motivos para usar isso. Currying é um processo de conversão de uma função que aceita n argumentos em n funções que aceitam apenas um argumento.
O princípio é passar os argumentos da função passada, usando a propriedade encerramento (fechamento), para armazená-los em outra função e tratá-la como um valor de retorno, e essas funções formam uma cadeia e os argumentos finais são passados para concluir a operação.
O benefício disso é que ele pode simplificar o processamento de parâmetros, lidando com um parâmetro de cada vez, o que também pode melhorar a flexibilidade e a legibilidade do programa. Isso também torna o programa mais gerenciável. Também dividir o código em partes menores tornaria o uso reutilizável.
Por exemplo:
Eu também posso fazer ...
Isso é ótimo para tornar o código complexo limpo e manipular métodos não sincronizados, etc.
fonte
Uma função ao curry é aplicada a várias listas de argumentos, em vez de apenas uma.
Aqui está uma função regular, sem curry, que adiciona dois parâmetros Int, xey:
Aqui está uma função semelhante que é curry. Em vez de uma lista de dois parâmetros Int, você aplica esta função a duas listas de um parâmetro Int cada:
O que está acontecendo aqui é que, quando você invoca
curriedSum
, você recebe duas invocações de funções tradicionais consecutivas. A primeira chamada de função usa um único parâmetro Int chamadox
e retorna um valor de função para a segunda função. Esta segunda função aceita o parâmetro Inty
.Aqui está uma função chamada
first
que faz em espírito o que a primeira chamada de função tradicionalcurriedSum
faria:A aplicação de 1 à primeira função - em outras palavras, invocando a primeira função e passando em 1 - produz a segunda função:
A aplicação de 2 à segunda função produz o resultado:
fonte
Um exemplo de curry seria ao ter funções que você conhece apenas um dos parâmetros no momento:
Por exemplo:
Aqui, como você não conhece o segundo parâmetro para retorno de chamada ao enviá-
performAsyncRequest(_:)
lo, seria necessário criar outro lambda / encerramento para enviá-lo à função.fonte
func callback
voltando? Ele está sendo chamado @callback(str)
assimlet callback = callback(str)
, callback é apenas o valor de retornofunc callback
func callback(_:data:)
aceita dois parâmetros, aqui eu só dou um, oString
, então ele está aguardando o próximo (NSData
), é por isso que agoralet callback
existe outra função aguardando aAqui está o exemplo da versão genérica e a mais curta para currying de funções com n não. de params.
fonte
Aqui você pode encontrar uma explicação simples sobre a implementação de currying em C #. Nos comentários, tentei mostrar como o curry pode ser útil:
fonte
O curry é uma das funções de ordem superior do Java Script.
Currying é uma função de muitos argumentos que são reescritos de modo que ele pegue o primeiro argumento e retorne uma função que, por sua vez, usa os argumentos restantes e retorna o valor.
Confuso?
Vamos ver um exemplo,
Isso é semelhante à seguinte função de curry,
Então, o que esse código significa?
Agora leia a definição novamente,
Currying é uma função de muitos argumentos que são reescritos de modo que ele pegue o primeiro argumento e retorne uma função que, por sua vez, usa os argumentos restantes e retorna o valor.
Ainda confuso? Deixe-me explicar profundamente!
Quando você chama essa função,
Ele retornará uma função como esta,
Portanto, isso é chamado de funções de ordem superior. Significado, invocar uma função em turnos retorna outra função é uma definição exata para a função de ordem superior. Essa é a maior vantagem da legenda, Java Script. Então volte para o curry,
Essa linha passará o segundo argumento para a função curryAdd.
que por sua vez resulta,
Espero que você entenda o uso do curry aqui. Então, aproveitando as vantagens,
Por que currying?
Faz uso de reutilização de código. Menos código, menos erro. Você pode perguntar como é menos código?
Eu posso provar isso com o script ECMA 6, novas funções de seta.
Sim! ECMA 6, forneça o maravilhoso recurso chamado funções de seta,
Com a ajuda da função de seta, podemos escrever a função acima da seguinte maneira:
Legal certo?
Então, menos código e menos bugs !!
Com a ajuda dessas funções de ordem superior, é possível desenvolver facilmente um código sem erros.
Eu desafio-te!
Espero que você entenda o que está currying. Por favor, sinta-se livre para comentar aqui se precisar de algum esclarecimento.
Obrigado, tenha um bom dia!
fonte
Há um exemplo de "Currying in ReasonML".
fonte