Escriba una función, f
que tome un entero positivo y devuelva una función.
La nueva función devuelta debe ser idéntica a f
. Sin embargo, cuando ocurre la "llamada de terminación", f
debería devolver la suma de todos los enteros pasados.
Por ejemplo, g=f(4)
(si f
es la primera función) debería establecerse g
en otra función. h=g(3)
Hará lo mismo. Sin embargo, cuando llama h
sin argumentos (consulte los detalles a continuación), debería generar 7, ya que es la suma de los argumentos de la función anterior. Dicho de otra manera, f(3)(4)() == 7
.
Tenga en cuenta que esto no es lo mismo que f(3,4)()
.
La "llamada de terminación" es una de las siguientes opciones (su elección):
- llamar sin argumentos
- nulo como argumento
- cualquier valor no positivo
Se debe admitir una cantidad arbitraria de llamadas a funciones, no hay un límite predefinido.
Se garantiza que la suma total no será mayor a 1'000.
Podemos suponer que se realiza al menos una llamada antes de la "llamada de terminación".
Su código no debe usar variables estáticas por programa, por lo que debería ser posible ejecutar el experimento varias veces en el mismo tiempo de ejecución y observar exactamente el mismo comportamiento.
Ejemplos:
f(1)() == 1
f(4)(2)(7)() == 13
f(4)(2)(7)(5)(2)() == 20
fuente
f(4)
devuelve una nueva función. Si esa nueva función se llama sin argumentos, regresa4
, pero si se llama con otro argumento, nuevamente devolverá una nueva función con la misma semántica pero con el nuevo argumento agregado al4
y así sucesivamente.q = f(2)(3); b = f(1)(2)(3); q(); b()
?Respuestas:
JavaScript (ES6), 18 bytes
Pase un valor falso para recuperar la suma. Se podrían permitir ceros por un costo de 2 bytes.
Pruébalo en línea
Sin golf:
fuente
Haskell (GHC), 118 bytes
Esto es 98 bytes para el código y 20 bytes para el indicador del compilador GHC
-XFlexibleInstances
, que permite una extensión de sistema de tipo.Esto define una "función"
f
, que se puede llamar con un número arbitrario de enteros seguido de la unidad()
, después de lo cual devuelve un entero. Se requieren anotaciones de tipo. Pruébalo en línea!Explicación
Forzar el estricto sistema de tipos de Haskell para permitir esto requiere algo de magia, es decir, habilitar la extensión GHC para instancias de tipo de clase flexible. Cómo funciona esto es que
f
es una función polimórfica paramétrica restringida por una restricción de clase de tipo: su tipo esF a => Int -> a
. Esto significa quef
toma un número entero y devuelve un valor de tipoa
, para cualquier tipoa
que pertenezca a la clase de tiposF
.F
es solo el nombre de la clase de tipos que proporciona la funciónf
; Se declara en la primera línea.Las siguientes dos líneas son dos instancias de
F
para diferentes tiposa
. La segunda línea indica que el tipo de funciones de()
a enteros perteneceF
(donde()
es el tipo de unidad cuyo único miembro es el valor()
), y la implementación esf n () = n
; la función devuelve su primer argumento. La última línea indica que sia
pertenece aF
, entonces también lo hace el tipo de funciones de enteros aa
: de una funciónf :: Int -> a
podemos generar otra funciónf :: Int -> Int -> a
. La implementación esf m n = f (m+n)
(el código usa combinadores para acortarlo), donde elf
de la izquierda es el nuevo y elf
de la derecha es el antiguo. Esto esencialmente daf
un nuevo argumento entero, que se agrega al siguiente. Múltiples argumentos se resumen así:El
f
en cada línea tiene un tipo diferente.Las funciones de Haskell se ejecutan automáticamente, por lo que si
f
solo da enteros, obtendrá una función.fuente
f
, ni una sola función que hace el trabajo. Sin embargo, esto es lo más cerca que puede estar en Haskell. No creo que sea posible resolver la tarea con una sola función debido al estricto sistema de tipos.f
, sino infinitas funciones llamadasf
. (Uno para cada posible número de argumentos). Estas funciones (de esta familia infinita) tienen dos tipos de definiciones, una cuando el número de argumentos es cero y otra cuando no lo es.f n()=n
yf=(f.).(+)
, por lo tanto, lo llamaría definir dos funciones.g 0 = 1
yg n = g (n-1) * n
, donde hay dos definiciones pero solo una función. Aquí tenemos dos definiciones pero infinitas funciones. (Cada uno de un tipo diferente.)ghci
cargue lo anterior e intente:t f
: diráf :: F a => Int -> a
(lo que significa que sia
es una instancia de clasef
, entoncesf
es una funciónInt -> a
). Por lo tanto, podríamos considerar esto como una función o infinitamente muchas, pero aunque tiene dos tipos de definiciones (al igual que la función factorial), no veo ninguna buena base para considerar que son dos funciones.Python 2,
424136 bytesEsta solución nunca tendrá un desbordamiento, ya que Python admite enteros de precisión arbitraria. Cero es el "valor especial".
Pruébalo en línea
Sin golf:
fuente
C,
6258 bytes, compitiendo en el límite¡Guardado 4 bytes gracias a Kevin! (Todavía no se elimina typedef porque es algo necesario para ser llamado).
La función para llamar es
f
; deja de llamarlo y obtiene el resultado llamándolo con un número no positivo como0
. ¡Pruebe un arnés de prueba en línea!Entonces, hasta donde puedo decir, la única forma de "curry" funciones que tienen múltiples tipos de retorno es hacer una de las siguientes:
union
/struct
type que tenga unint
subtipo y una función / autorreferencial.Intenté hacer (2), pero parecía un poco en contra del espíritu de la pregunta y, francamente, casi imposible de hacer. Por lo tanto, de acuerdo con el espíritu del desafío, he optado por la opción (1). Esto requiere convertir cada función devuelta en una función, para que pueda usarse.
Esta sintaxis de "curry" parece un poco extraña, pero es bastante similar. Para emular
f(21)(1)
, uno tendría que escribir((B)((B)f(21))(1))(0)
. Definí elB
tipo como una función que toma un número entero y devuelve un puntero a una función que toma un número entero. Ampliado, esto se ve así:fuente
q;f(x){return x?(q+=x,f):q;}
.q
después de cada ejecución, entonces la función ya no sería utilizableMathematica, 25 bytes
Pruébalo en línea! (Usando matemáticas).
Es posible hacer tres bytes menos portando la respuesta de JavaScript, pero quería presentar una solución de Mathematica más idiomática. El
@
es solo un poco de azúcar sintáctica, lo que hace que la solución sea equivalente a:Entonces, sí, la idea es que en Mathematica no solo puede definir una función,
f[x_]
sino que puede adjuntar directamente un valor a una expresión más complicada que contengaf
, por ejemplo,f[x_]
pasar otro argumento. Al configurar dos definiciones para esto, podemos obtener el comportamiento deseado:f[x][y]
llamadaf[x+y]
, consumiendo así una "llamada" y sumando los argumentos dentro. Esta regla se aplica hasta que nos quedemosf[sum][]
.sum
.fuente
C ++, 72 bytes
Esto define un tipo
F
que actúa como la función solicitada, y una variablef
de ese tipo para invocar. Es válido a partir de C ++ 11 y funciona con versiones en línea de GCC, clang, icc y VC ++.Uso:
Explicación:
Después de preprocesar y reformatear, se ve así:
Esto normalmente se escribiría:
return a;
yreturn {+a};
hacer lo mismo, ya que unario+
no cambia el valor, y se permiten llaves redundantes alrededor del valor de retorno.int m
yint(m)
haga lo mismo, ya que se permiten paréntesis redundantes alrededor de un nombre de variable, incluidos los parámetros de función.return {m+a};
yreturn {int(m)+a};
hacer lo mismo, ya que un elenco dem
fromint
aint
no cambia su valor. Estos cambiosoperator()
acercan las dos sobrecargas en sintaxis, lo que permite invocar una sola definición de macro dos veces. Elegir el orden correcto para los tres miembros permite que la primera palabra de la siguiente línea (int
) se incluya también en la definición de macro.fuente
operator()
para hacer que este trabajo fuera especialmente genial.Ruby, 23 bytes
Uso:
fuente
C,
10496 bytesUtiliza el método del enlace que @JulianWolf ha compartido. El último argumento debe ser 0.
Pruébalo en línea!
fuente
Math.JS, 38 Bytes
Llámalo con
f(number_a)(number_b)(...)(negative_number)
Si se nos permite especificar la llamada inicial,
f(x)=i(x,0)\n
se pueden descartar 12 bytes ( ) y se puede llamar coni(number_one,0)(number_two)(...)(negative_number)
¡Intentalo!
Explicacion
Como se muestra en el LaTex anterior,
f(x)
simplemente llamai(x,0)
, luego,i(x,y)
devuelve el valor dey
ifx
es menor que 0, o la funciónj(z)=i(z,x+y)
, que toma un argumento, que se repite. Agregando al valor dey
.fuente
C,
232206 bytesProbablemente esto se pueda jugar significativamente, pero debería servir como prueba de concepto de que C se puede usar, sin ninguna extensión de lenguaje *, para resolver este problema llamando sin argumentos en lugar de con un valor mágico.
* @hvd ha notado que, si bien esto funciona de forma predeterminada con gcc, parte del comportamiento no está definido en el estándar C, lo que significa que puede no ser portátil. ¡Úselo bajo su propio riesgo!
Sin golf:
Compilación y ejecución con
gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-currying
salidas (después de algunas advertencias)fuente
g
yh
continuar una cadena de invocaciones de macros funcione, ya que no se especifica si el siguienteg
aparece en el contexto de la expansión del primerog
. C11 agrega un ejemplo a 6.10.3.4 para explicar que no está especificado. (IIRC, el preprocesador de TenDRA es uno que no lo expandiría de la manera que desee). Aparte de eso, ninguna versión del lenguaje admite argumentos de macro vacíos e int implícito, por lo que un programa C válido no puede usar ambos. :) Aún así, buena respuesta. ¿Estás buscando jugar más al golf?*s
lugar destrlen(s)
. Las cadenas C son de longitud implícita, terminadas por achar
con valor0
. Bonito macro hack para permitir llamadas con / sin un argumento!Código de máquina 8086, 27 bytes
Este código de máquina debe estar en la dirección 0x100, y asume el modelo de código pequeño (cs = ds = es = ss). Sin embargo, la ubicación de la función se puede cambiar sin costar bytes adicionales. Ponerlo en offset
0
ahorraría un byte (enxor si,si
lugar demov si, 0x100
)Convención de llamada requerida
Esto supone que la persona que llama ha asignado previamente al menos 27 bytes en la pila. Toma un número
ax
y devuelve un puntero de funciónbx
. Llamar a este puntero conax=0
termina la cadena y devuelve la sumabx
.Entonces para la primera llamada:
Luego, para cada llamada posterior:
Para terminar:
Ungolfed (desmontaje comentado del código de máquina):
Después de llamar a esto con AX distinto de cero,
bx = sp
y el búfer se llena con una copia modificada del código de la máquinafunction
. El inmediato de 16 bits en la primera instrucción contiene el total. (Está escrito por la última instrucción antes delret
.)push di
/pop bx
podría reemplazarse conmov bx, di
(antesrep movsb
), lo que lo hace más simple pero sin ahorros.Requerir que la persona que llama pase un puntero al búfer dst
di
ahorre 4 bytes en lugar de calcularlo en relación consp
.Hacer que la dirección de inicio de la función sea la misma que el tamaño de la función ahorraría un byte (
mov cx, si
).fuente
objdump -b binary
lugar dehexdump -C
di
(4 bytes). Haga que la función start address = size: enmov cx, si
lugar demov cx, 0x1b
.C #, 62 bytes
Para finalizar la llamada, pase un número negativo, p. Ej.
fuente
null
o sin parámetros para finalizar. Sin embargo, todas las formas en que lo intenté fueron mucho más largas!m
lugar dem<0
y pasarnull
o0
como el último parámetro?Boolean
se puede usar a comoBoolean
... Lo intenténull
pero se hizo más largo. Quería usar lo??
que significa que si LHS es nulo, haga RHS, pero como necesito si LHS no es nulo, haga esto, si no es RHS, no podría.Scala, 58 caracteres
Pruébalo en línea
Sin golf:
Explicación:
Este código define una
case class
f llamada con un constructor que toma un int. Defina una clase de caso que generará los métodos equals, hashcode, toString y copy, y un objeto complementario con el mismo nombre para permitir la creación de objetos sin lanew
palabra clave.Esta clase tiene un método de aplicación sobrecargado: uno toma otro entero para agregar y crea un nuevo objeto con la suma actualizada, y otro sin argumentos para obtener la suma.
En Scala, cualquier objeto con un método de aplicación se puede llamar como un método, es decir, se
o.apply(x)
puede escribir comoo(x)
. Esto se usa en la biblioteca estándar para matrices, listas, mapas y elFunction1
rasgo implementado por funciones anónimasfuente
Pyth, 19 bytes
Pruébalo en línea!
Estoy impresionado de que Javascript supere a Pyth, pero, de nuevo, Pyth no está diseñado para pasar funciones.
fuente
Perl 5, 36 bytes
fuente
-M5.016
? Parece que debería poder soltar-M5.016
y luego también soltarmy
y guardar un par de bytes. Si es justosay
, puede usar la bandera en su-E
lugar, que no se activause strict
, por lo que aún puede soltarlamy
.__SUB__
) pero cambié eso antes de enviar y no eliminé el bit alrededor de 5.16. Lo quitarémy
Sin embargo , no creo que dejarlo sea correcto.say
como parte del código, es solo para fines ilustrativos)my
sinuse strict
,$n
es implícitamente una variable global. Es una mala forma en los scripts de Perl adecuados, pero es bastante común en frases sencillas, y parece funcionar aquí.Brain-Flak , 6 bytes
En realidad, me acabo de dar cuenta de que, dado que ToS es un formato de retorno válido, no es realmente necesario el 0, lo que ahorra 2 bytes:
Pruébalo en línea!
Envío original (es), 8 bytes
Usos
0
como valor especial:Pruébalo en línea!
Explicación
Dados los argumentos a 1 , a 2 , ..., a n , 0 , la pila inicialmente se ve así:
un n
⋮
un 2
un 1
0 0
Luego, el código continúa, aparece cada a i , los acumula, aparece el 0, los agrega y empuja el resultado:
Soluciones alternativas, 8 bytes.
En lugar de hacer estallar el 0 y agregarlo a la suma, también podemos intercambiar pilas, ya que la correcta está inicialmente vacía:
Pruébalo en línea!
Usando la
-r
bandera, el 0 está en la parte superior de la pila, por lo que podríamos mostrarlo primero:Pruébalo en línea!
Pruébalo en línea!
fuente
C (GCC), 83 bytes
Mi primer golf C! Hay un par de otras soluciones de C, pero esta es un poco diferente. El uso del preprocesador es puramente cosmético. Este enfoque se discutió por primera vez en la respuesta de Conor O'Brien aquí .
El valor terminal es cero. El valor de retorno es una unión, por lo que para llamar al resultado, use el campo
f
y para acceder al valor final, use el campov
, por ejemploPruébalo en línea
Limitaciones
Una variable global contiene el total acumulado. Si bien esto se rechaza explícitamente, la presentación admite invocaciones repetidas (el total se restablece en la llamada terminal), lo que parece ser la razón de la prohibición del estado global.
Un puntero a
f
se almacena en la unión devuelta a través delint
miembro, por lo que claramente no es portátil. No estoy seguro de si esto funciona en GCC en todas las plataformas o solo en Linux o solo en x86 o solo con ELF o ... Si alguien conoce algún detalle sobre esto, ¡comente o envíe un mensaje!fuente
APL (Dyalog Classic) ,
48474644 32 bytesPruébalo en línea!
Termina pasando en cero. Sintaxis de llamada:
((0 f 1) 2) 0
-15 bytes gracias a @ngn
Requiere
⎕IO←0
¡Cualquier consejo de golf es bienvenido!
fuente
:If x<0
a:If×x
e intercambiar los "si" y "cláusulas else"r←⍎condition⊃'else' 'then'
Perl 6 , 31 bytes
fuente
Dyvil , 34 bytes
Uso :
El final
()
puede ser omitido.Explicacion :
Define un operador de yuxtaposición que toma dos entradas y las agrega. El parámetro
j
tiene el valor predeterminado0
para admitir la llamada sin argumentos. El0
en los ejemplos anteriores no es el nombre, sino un literal.fuente
Julia v0.5 +, 52 bytes
Llamar como
F
. Probablemente esto podría hacerse mucho más corto adoptando un método menos OO, pero siempre me gusta tener la oportunidad de usar este idioma.Si se puede suponer que "se realizará al menos una llamada antes de la llamada de terminación", la segunda línea se puede eliminar para guardar 6 bytes.
fuente
Julia 0.5 , 18 bytes
Pruébalo en línea!
fuente
R, 40 bytes
0 actúa como el valor de parada aquí. Para dos bytes más, podemos omitirlo.
El problema es que R carece de una lambda incorporada concisa. Pero si agregamos uno , podemos obtener el código a 26 bytes :
(Sí, eso es válido R. Solo necesita una importación).
fuente
PHP, 44 bytes
Una idea de @ user63956
Llamada de terminación
0
Versión en línea
Llamada de terminación con
NULL
necesidad de un càst[$i]
para[+$i]
PHP, 47 bytes
Versión en línea
PHP, 52 bytes
Llamada de terminación
NULL
o cualquier otro valor que sea falso en PHPsi el programa debe finalizar después de que la salida se reemplace
print$s
condie("$s")
+ 2 bytesVersión en línea
fuente
$s
. para que pudieras hacer algo comoreturn$i?f:$s
al finalfunction f($i){return[$_GET[0]+=$i][$i]?:f;}
.PowerShell, 86 bytes
Pruébalo en línea!
Código de prueba:
Salida: 20
fuente
$n="$args"
lugar de$n=$args[0]
. Sin$args[0]
embargo, no funcionará en el otro , porque entonces obtendrá la concatenación de cadenas en lugar de la adición.Python 3 , 63 bytes
Pruébalo en línea!
Termina con 0
fuente
Python, 69 bytes
fuente
Octava, 39 bytes
* El argumento de la llamada de terminación es 0.
Pruébalo en línea!
*
endfunction
requerido para agregar algunos otros códigos.fuente
R,
5452 bytes¡Ahorré 2 bytes gracias a MickyT!
Similar a una de las respuestas de Python. Sin golf:
Corre como
fuente
f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
return
.return
en R no es lo mismo que en otros idiomas, realiza un aborto prematuro. No usarreturn
es idiomático. Por otro lado, su versión sin golf todavía tiene el golfif
.if
fue pereza, peroreturn
es solo por legibilidad: da el mismo resultado con o sinreturn
.return
disminuye la legibilidad porque señala algo incorrecto (salida prematura) y es una instancia de programación de culto de carga .C ++ (gcc) ,
9591 bytesPruébalo en línea!
fuente