Ter uma função f que recebe argumentos x 1 , x 2 ,…, x n
- ie. f: X 1 × X 2 ×… × X n → Y
- currying redefine f como uma função usando um único argumento a 1 que mapeia para outra função. Essa técnica é útil para aplicação parcial, por exemplo, com uma pow
função ao curry que poderíamos escrever exp = pow(e)
.
Exemplo
Assumindo que temos a seguinte função f usando três argumentos ( f: X 1 × X 2 × X 3 → Y ):
def f(a,b,c):
return a + b * c
A seleção dessa função nos deixa com f_curry: X 1 → (X 2 → (X 3 → Y)) , se agora chamarmos essa função duas vezes, obteríamosf_curry(1)(2)
uma função ( h
) equivalente ao seguinte retornado:
def h(c):
return 1 + 2 * c
A função ao curry f
pode ser escrita assim (Python 3):
def f_curry(a):
def g_curry(b):
def h(c):
return a + b * c
return h
return g_curry
Desafio
Seu desafio será curry uma função como descrito acima, aqui estão as regras:
- Entrada será uma função de caixa preta que requer pelo menos 2 argumentos
- A função de entrada sempre terá um número fixo de argumentos (diferente
printf
ou semelhante, nota: você precisa suportar funções com qualquer número de argumentos ≥2) - Se o seu idioma usa funções com caril por padrão (por exemplo, Haskell), você pode esperar que a função de entrada seja definida sobre N- pares, em vez de uma "função de ordem superior"
- Você pode usar o número de argumentos como entrada
- A saída será o equivalente ao curry da entrada *
- Você pode assumir que a função de saída será sempre:
- chamado com menor ou igual ao número de argumentos que a função de entrada leva
- chamado com argumentos do tipo certo
* Isso significaria para uma entrada f
com N
argumentos e uma saída h
que, para todos os argumentos válidos, a1,…,aN
ela contenha isso f(a1,a2,…,aN) == h(a1)(a2)…(aN)
.
def f(a,b,c): return a + b * c
e a saída édef f_curry(a): def g_curry(b): def h(c): return a + b * c return h return g_curry
?f
(que é definida em algum lugar) e a saída deve ser algo equivalentef_curry
. Ou a entrada serialambda a,b,c: a+b*c
e a saída uma função equivalente af_curry
.Respostas:
JavaScript (ES6), 35 bytes
fonte
Idris , 204 bytes
Experimente online!
Parece um trabalho para tipos dependentes! Bem, talvez.
C é uma função do tipo curry. Dado um vetor dos tipos a = [t 1 , t 2 ,… t n ] e uma função de tipo T: HVect a → Type , ele retorna um novo tipo:
Aqui, HVect é o tipo de vetor heterogêneo do Idris Prelude - o tipo de n- pares cujos elementos são de n tipos diferentes.
c é uma função que recebe um e T como argumentos implícitas, e, em seguida, converte um uncurried função
f
do tipo ((b: HVect um) → T b) em uma curried um de tipo C de um T .( C simplesmente descreve o que queremos fazer; c realmente faz isso. Mas não podemos deixar de definir C , pois Idris exige que todas as definições de nível superior tenham uma assinatura de tipo.)
O link TIO fornece um exemplo de uso. Se definirmos uma função em três tuplas (Nat, Nat, String) da seguinte maneira:
então
uncurried [3, 4, "th"]
gera o mesmo resultado quec uncurried 3 4 "th"
. Idris deduz os argumentosa=[Nat, Nat, String]
e,T=const String
para nós, acredito.Baseei este código nesta essência por timjb.
fonte
HVect
por padrão -HVect
é essencialmente uma tupla que você pode desconectar.Python 3 ,
5453 bytesExperimente online!
fonte
R , 96 bytes
Experimente online!
Versão anterior (97 bytes)
-1 byte graças a @JayCE
fonte
Coco , 54 bytes
Experimente online!
Coco , 40 bytes
Resposta do Python do porto de Erik .
Experimente online!
fonte
Python 2 , 60 bytes
Experimente online!
O rodapé é um testador que usa STDIN da seguinte maneira por linha:
[a,b,...]
)Observe que, enquanto uma lista dos argumentos é fornecida como entrada no testador, na realidade, o equivalente ao curry é anexado à lista e a lista é reduzida por chamada de função.
Uma versão semelhante de 55 bytes foi gentilmente fornecida por ovs :
Experimente online!
fonte
Couve-flor , 84 bytes
Experimente online!
fonte
Perl 6 ,
4240 bytesExperimente online!
-2 bytes graças a Brad Gilbert b2gills .
fonte
*
, só é necessário se houver algo depois dele.assuming(*,1)
.Python 2 , 78 bytes
Experimente online!
fonte
Anexo , 5 bytes
Experimente online!
Simples construído, em grande parte desinteressante. Mas, aqui está uma versão do zero:
Anexo, 35 bytes
Explicação:
fonte
Java 8, 46 + 318 = 364 bytes
Este é um lambda com curry (hah) que recebe uma função e uma contagem de argumentos e retorna a função com curry.
Experimente Online
Tipo de envio
Função de entrada
A entrada da função é um objeto com um único método (excluindo métodos herdados) representando a função. Observe que uma interface funcional padrão não pode ser usada como o tipo de entrada, porque funções de (por exemplo) 3 parâmetros devem ser suportadas. Observe também que uma expressão lambda convertida em um
java.util.function.Function
tipo padrão pode ser passada (o método único éapply
).As exceções marcadas podem ser declaradas na função de entrada, mas não podem ser lançadas (ou seja, não serão propagadas para o chamador da função de saída). Presume-se que isso seja aceitável porque as interfaces funcionais do Java não permitem exceções verificadas (e sua propagação impediria o envio de retornar a
Function
). As exceções de tempo de execução (atribuíveis aRuntimeException
ouError
) são propagadas.Função de saída
A saída da submissão é a
java.util.function.Function<Object, Object>
. Eu considerei retornar uma planícieObject
com umapply
método (como na entrada), mas a reflexão seria necessária para invocar o resultado, o que parecia inconveniente o suficiente para ser desaprovável - em particular, chamar o tempo todo não seria mais possível em um único expressão.Uso
Como o envio retorna uma função de
Object
paraObject
, a saída pode ser chamada diretamente (comapply
), mas os valores de retorno intermediários subsequentes devem ser convertidos em um tipo apropriado (por exemplojava.util.function.Function<Object, Object>
) antes de serem chamados. Consulte o TIO para obter alguns exemplos de uso.Observe que nas funções Java (ou seja, métodos) não são objetos de primeira classe. Portanto, a sintaxe usada no marcador de saída da descrição do desafio não tem sentido em Java. Mais do
f(a1, a2, a3)
que temosf.apply(a1, a2, a3)
, e mais dof(a1)(a2)(a3)
que temosf.apply(a1).apply(a2).apply(a3)
.Limitações
Quando um resultado intermediário é aplicado (um argumento adicionado), o resultado é na verdade uma cópia modificada do resultado original. Por exemplo, neste trecho:
a linha 4 seria impressa
4
, mas a linha 5 falharia, porque nessa épocac2
já contém argumentos2
e2
(observe também issoc2 == c
). Isso viola o espírito de curry, mas atende aos requisitos específicos declarados no desafio.Ungolfed
Veja o TIO para obter uma cópia não destruída.
fonte
Julia 0,6 , 48 bytes
Experimente online!
Porto da resposta em Python do @ EricTheOutgolfer.
fonte
APL (Dyalog Classic) ,
5857 bytesExperimente online!
Sintaxe de chamada (com função ao curry
g
, argumentosx1
atéx3
e número de argumentosn
):((n x1 f g) x2) x3
Requer
⎕IO←1
fonte