Curry de longitud arbitraria

53

Escriba una función, fque 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", fdebería devolver la suma de todos los enteros pasados.

Por ejemplo, g=f(4)(si fes la primera función) debería establecerse gen otra función. h=g(3)Hará lo mismo. Sin embargo, cuando llama hsin 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
Eugene D. Gubenkov
fuente
44
@LuisMendo Generalmente significa que f(4)devuelve una nueva función. Si esa nueva función se llama sin argumentos, regresa 4, pero si se llama con otro argumento, nuevamente devolverá una nueva función con la misma semántica pero con el nuevo argumento agregado al 4y así sucesivamente.
Martin Ender
66
@LuisMendo De hecho, depende de Eugene, pero creo que permitir llamadas repetidas eliminaría significativamente el desafío, porque la parte interesante no es hacer una función con estado, sino hacer una función de orden superior.
Martin Ender
66
@MartinEnder Eso tiene mucho sentido. Eugene, si esa es la intención, cambia la redacción del desafío. Escribir una función a la que se pueda llamar infinitamente no sugiere en absoluto que la función deba devolver una función
Luis Mendo
44
¿Podemos suponer que solo habrá una instancia de la cadena de llamadas a la vez? Por ejemplo, no q = f(2)(3); b = f(1)(2)(3); q(); b()?
Conor O'Brien
3
Habiendo recogido recientemente a Haskell, me interesa saber si esto es posible en Haskell. El sistema de tipo fuerte me hace pensar que podría no serlo.
CAD97

Respuestas:

49

JavaScript (ES6), 18 bytes

f=n=>m=>m?f(m+n):n

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:

f = function(n) {
    return function(m) {
        if (m) {
            return f(m+n);
        } else {
            return n;
        }
    }
}
Neil
fuente
Brillante sumisión!
Eugene D. Gubenkov
21

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.

class F a where f::Int->a
instance F(()->Int)where f n()=n
instance F a=>F(Int->a)where f=(f.).(+)

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 fes una función polimórfica paramétrica restringida por una restricción de clase de tipo: su tipo es F a => Int -> a. Esto significa que ftoma un número entero y devuelve un valor de tipo a, para cualquier tipo aque pertenezca a la clase de tipos F. Fes solo el nombre de la clase de tipos que proporciona la función f; Se declara en la primera línea.

Las siguientes dos líneas son dos instancias de Fpara diferentes tipos a. La segunda línea indica que el tipo de funciones de ()a enteros pertenece F(donde ()es el tipo de unidad cuyo único miembro es el valor ()), y la implementación es f n () = n; la función devuelve su primer argumento. La última línea indica que si apertenece a F, entonces también lo hace el tipo de funciones de enteros a a: de una función f :: Int -> apodemos generar otra función f :: Int -> Int -> a. La implementación es f m n = f (m+n)(el código usa combinadores para acortarlo), donde el fde la izquierda es el nuevo y el fde la derecha es el antiguo. Esto esencialmente dafun nuevo argumento entero, que se agrega al siguiente. Múltiples argumentos se resumen así:

  f  a1   a2   a3   a4   a5  ()
= f (a1 + a2)  a3   a4   a5  ()
= f (a1 + a2 + a3)  a4   a5  ()
= f (a1 + a2 + a3 + a4)  a5  ()
= f (a1 + a2 + a3 + a4 + a5) ()
=    a1 + a2 + a3 + a4 + a5

El fen cada línea tiene un tipo diferente.

Las funciones de Haskell se ejecutan automáticamente, por lo que si fsolo da enteros, obtendrá una función.

Zgarb
fuente
1
Tal vez estoy jugando, pero no es exactamente lo que pide el desafío. Estás definiendo dos (!) Funciones, ambas llamadas 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.
nimi
3
@nimi Esto define no dos funciones llamadas f, sino infinitas funciones llamadas f. (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.
ShreevatsaR
@ShreevatsaR: Veo dos definiciones f n()=ny f=(f.).(+), por lo tanto, lo llamaría definir dos funciones.
nimi
77
@nimi Hay dos definiciones, pero no dos funciones. El número de definiciones no necesita ser el número de funciones. Por ejemplo, puede definir la función factorial con las dos definiciones g 0 = 1y g 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.)
ShreevatsaR
1
@nimi Por cierto, ghcicargue lo anterior e intente :t f: dirá f :: F a => Int -> a(lo que significa que si aes una instancia de clase f, entonces fes una función Int -> 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.
ShreevatsaR
15

Python 2, 42 41 36 bytes

Esta solución nunca tendrá un desbordamiento, ya que Python admite enteros de precisión arbitraria. Cero es el "valor especial".

f=lambda n:lambda m:m and f(m+n)or n

Pruébalo en línea

Sin golf:

def f(n):
    def g(m=''):
        return f(m+n)if m<''else n
    return g
mbomb007
fuente
14

C, 62 58 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).

typedef(*(*B)(_))(_);q;f(x,o,_){x=x?(q+=x,f):(x=q,q=0,x);}

La función para llamar es f; deja de llamarlo y obtiene el resultado llamándolo con un número no positivo como 0. ¡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:

  1. Transmita el resultado a una función para decirle al compilador que desea volver a llamar al resultado;
  2. o cree un union/ structtype que tenga un intsubtipo 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í el Btipo 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í:

   ( (B)( (B) f(21) )(1) )(0)
//            f(21)            - call f with 21
//        (B)                  - cast to B, a function pointer
//      (           )(1)       - call with 1
//   (B)                       - cast to a function pointer
// (                     )(0)  - call with 0
Conor O'Brien
fuente
Si dice que termina solo en 0, va a requerir la conversión (lo que hace en C porque C no puede definir correctamente una función que se devuelve), y deja borrar el global entre ejecuciones para la persona que llama (que Creo que es perfectamente razonable), puedes simplificar todo q;f(x){return x?(q+=x,f):q;}.
Kevin
1
@Kevin todavía, según las reglas del sitio, una función debe ser reutilizable. Si no hice cero qdespués de cada ejecución, entonces la función ya no sería utilizable
Conor O'Brien
Tal vez los punteros de función? Tendría que hacer una referencia cada vez, pero podría valer la pena echarle un vistazo
Downgoat
1
@ ConorO'Brien Acabo de implementar su enfoque sindical. Es más largo que este, pero no está lejos.
Jakob
13

Mathematica, 25 bytes

f[x_]@y_=f[x+y]
f[x_][]=x

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:

f[x_][y_]=f[x+y]
f[x_][]=x

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 contenga f, por ejemplo, f[x_]pasar otro argumento. Al configurar dos definiciones para esto, podemos obtener el comportamiento deseado:

  • La primera definición colapsa una f[x][y]llamada f[x+y], consumiendo así una "llamada" y sumando los argumentos dentro. Esta regla se aplica hasta que nos quedemos f[sum][].
  • La segunda definición desempaqueta este caso final definiendo todo para evaluar sum.
Martin Ender
fuente
1
<3 programación simbólica
Julian Wolf
8

C ++, 72 bytes

#define O(P)operator()(P){return{P+a};}int
struct F{F O(int(m))O()a;}f;

Esto define un tipo Fque actúa como la función solicitada, y una variable fde 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:

int main() {
  return f(1)(2)(3)(); // returns 6
}

Explicación:

Después de preprocesar y reformatear, se ve así:

struct F {
  F operator()(int(m)) { return{int(m)+a}; }
  int operator()() { return {+a}; }
  int a;
} f;

Esto normalmente se escribiría:

struct F {
  F operator()(int m) { return {m+a}; }
  int operator()() { return a; }
  int a;
} f;

return a;y return {+a};hacer lo mismo, ya que unario +no cambia el valor, y se permiten llaves redundantes alrededor del valor de retorno. int my int(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};y return {int(m)+a};hacer lo mismo, ya que un elenco de mfrom inta intno cambia su valor. Estos cambios operator()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.

hvd
fuente
1
Hermosa. Y no solo la solución de golf ... la sobrecarga operator()para hacer que este trabajo fuera especialmente genial.
Ray Toal
6

Ruby, 23 bytes

f=->n{->m{m ?f[n+m]:n}}

Uso:

f[1][2][3][nil]
=> 6
daniero
fuente
6

C, 104 96 bytes

#define a(i)s(i)|b
#define b(i)u(i)|c
#define c(i)u(i)|b
b,c,d;s(i){b=c=i;i=d;}u(i){c=b+=i;i=d;}

Utiliza el método del enlace que @JulianWolf ha compartido. El último argumento debe ser 0.

Pruébalo en línea!

Betseg
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Dennis
4

Math.JS, 38 Bytes

f(x)=i(x,0)
i(x,y)=x<0?y:j(z)=i(z,y+x)

Llámalo con f(number_a)(number_b)(...)(negative_number)

Si se nos permite especificar la llamada inicial, f(x)=i(x,0)\nse pueden descartar 12 bytes ( ) y se puede llamar coni(number_one,0)(number_two)(...)(negative_number)

¡Intentalo!

Explicacion

¡Látex!

Como se muestra en el LaTex anterior, f(x)simplemente llama i(x,0), luego, i(x,y)devuelve el valor de yif xes menor que 0, o la función j(z)=i(z,x+y), que toma un argumento, que se repite. Agregando al valor de y.

Un taco
fuente
4

C, 232 206 bytes

#include<string.h>
#include<stdlib.h>
#define f(X)s(""#X)?0:g
#define g(X)u(""#X)?0:h
#define h(X)u(""#X)?0:g
g=0,h=0;s(char*s){g=h=atoi(s);return 0;}u(char*s){char*a=strlen(s)?s:"0";g=h+=atoi(a);return 0;}

Probablemente 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:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define f(X) start("" #X) ? 0 : f0
#define f0(X) update("" #X) ? 0 : f1
#define f1(X) update("" #X) ? 0 : f0

long f0 = 0;
long f1 = 0;

int start(const char *s) {
    f0 = f1 = strtol(s, NULL, 10);

    return 0;
}

int update(const char *s) {
    const char *a = strlen(s) ? s : "0";
    f0 = f1 += strtol(a, NULL, 10);

    return 0;
}

int main() {
    printf("f(1)()          -> %ld\n", f(1)());
    printf("f(1)(2)(0)(3)() -> %ld\n", f(1)(2)(0)(3)());
    printf("f(1)(-2)(3)()   -> %ld\n", f(1)(-2)(3)());
    printf("f()             -> %ld\n", f());

    return 0;
}

Compilación y ejecución con gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingsalidas (después de algunas advertencias)

f(1)()          -> 1
f(1)(2)(3)(0)() -> 6
f(1)(-2)(3)()   -> 2
f()             -> 0
Julian Wolf
fuente
"sin extensiones de lenguaje": no se garantiza que el truco de alternar gy hcontinuar una cadena de invocaciones de macros funcione, ya que no se especifica si el siguiente gaparece en el contexto de la expansión del primero g. 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?
hvd
@hvd: sí, probablemente volveré en un par de días y veré si puedo jugar golf. Definitivamente tiene razón en que este es un comportamiento no especificado, pero creo que el tratamiento estándar aquí es que los lenguajes se definen por su implementación, por lo que siempre que funcione con gcc, estoy feliz.
Julian Wolf
Estaba abordando el comentario que incluyó en su respuesta de que no se basa en ninguna extensión de idioma. Sí, incluso con extensiones de idioma, es perfectamente válido como respuesta aquí, no quería sugerir lo contrario.
hvd
Ah, eso es definitivamente justo. Tienes razón en que debería estipular que, aunque no se requieren banderas adicionales, esto puede no ser portátil.
Julian Wolf
Puede probar la cadena vacía con en *slugar de strlen(s). Las cadenas C son de longitud implícita, terminadas por a charcon valor 0. Bonito macro hack para permitir llamadas con / sin un argumento!
Peter Cordes
4

Código de máquina 8086, 27 bytes

00000000  bb 00 00 85 c0 74 13 01  d8 be 00 01 89 e7 47 47  |.....t........GG|
00000010  57 b9 1b 00 f3 a4 5b 89  47 01 c3                 |W.....[.G..|
0000001b

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 0ahorraría un byte (en xor si,silugar de mov 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 axy devuelve un puntero de función bx. Llamar a este puntero con ax=0termina la cadena y devuelve la suma bx.
Entonces para la primera llamada:

mov bp, sp
sub sp, 28
mov ax, number_to_add
call function
; new function pointer in bx

Luego, para cada llamada posterior:

sub sp, 28
mov ax, number_to_add
call bx
; new function pointer in bx

Para terminar:

mov ax, 0
call bx
; result in bx
mov sp, bp

Ungolfed (desmontaje comentado del código de máquina):

00000000  BB0000            mov bx,0x0      ; 0 is replaced after copying
00000003  85C0              test ax,ax
00000005  7413              jz 0x1a         ; if(ax==0) ret (with value in bx)
00000007  01D8              add ax,bx       ; arg += total
00000009  BE0001            mov si,0x100    ; address of the original: ds:0x100
0000000C  89E7              mov di,sp
0000000E  47                inc di
0000000F  47                inc di          ; dst = sp+2 = above return address
00000010  57                push di
00000011  B91B00            mov cx,0x1b
00000014  F3A4              rep movsb         ; copy the function code.
00000016  5B                pop bx            ; bx = start of copy destination
00000017  894701            mov [bx+0x1],ax   ; update total in the copied code
0000001A  C3                ret               ; with bx = function pointer

Después de llamar a esto con AX distinto de cero, bx = spy el búfer se llena con una copia modificada del código de la máquina function. El inmediato de 16 bits en la primera instrucción contiene el total. (Está escrito por la última instrucción antes del ret.)

push di/ pop bxpodría reemplazarse con mov bx, di(antes rep movsb), lo que lo hace más simple pero sin ahorros.

Requerir que la persona que llama pase un puntero al búfer dst diahorre 4 bytes en lugar de calcularlo en relación con sp.

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).

usuario5434231
fuente
Esta sería una mejor respuesta si incluyera el desmontaje de los bytes del código de máquina. Las respuestas de código de máquina definitivamente necesitan una versión no adaptada. por ejemplo, usar en objdump -b binarylugar dehexdump -C
Peter Cordes
Actualizado con desmontaje comentado. Posibles ahorros: requiere que la persona que llama pase un puntero dst di(4 bytes). Haga que la función start address = size: en mov cx, silugar de mov cx, 0x1b.
Peter Cordes
2

C #, 62 bytes

dynamic f(int n)=>(System.Func<int,dynamic>)(m=>m<0?n:f(n+m));

Para finalizar la llamada, pase un número negativo, p. Ej.

f(1)(2)(3)(-1) == 6
TheLethalCoder
fuente
Me gustaría hacer que funcione pasando nullo sin parámetros para finalizar. Sin embargo, todas las formas en que lo intenté fueron mucho más largas
TheLethalCoder el
¿Se puede usar en !mlugar de m<0y pasar nullo 0como el último parámetro?
betseg
@betseg No en C # solo Booleanse puede usar a como Boolean... Lo intenté nullpero 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.
TheLethalCoder
2

Scala, 58 caracteres

case class f(n:Int){def apply(m:Int)=f(n+m)
def apply()=n}

Pruébalo en línea

Sin golf:

case class f(n:Int){
  def apply(m:Int)=f(n+m)
  def apply()=n
}

Explicación:

Este código define una case classf 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 la newpalabra 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 como o(x). Esto se usa en la biblioteca estándar para matrices, listas, mapas y el Function1rasgo implementado por funciones anónimas

corvus_192
fuente
2

Pyth, 19 bytes

DhdDebR?bh+dbdR$end

Pruébalo en línea!

Estoy impresionado de que Javascript supere a Pyth, pero, de nuevo, Pyth no está diseñado para pasar funciones.

Steven H.
fuente
2

Perl 5, 36 bytes

sub f{my$n=pop;sub{@_?f($n+pop):$n}}

say f(1)->(); # 1
say f(1)->(2)->(3)->(); # 6
hobbs
fuente
¿Qué hay de esto requiere -M5.016? Parece que debería poder soltar -M5.016y luego también soltar myy guardar un par de bytes. Si es justo say, puede usar la bandera en su -Elugar, que no se activa use strict, por lo que aún puede soltarla my.
Chris
@ Chris tiene razón, no necesita 5.16, mi revisión inicial sí (usando __SUB__) pero cambié eso antes de enviar y no eliminé el bit alrededor de 5.16. Lo quitaré mySin embargo , no creo que dejarlo sea ​​correcto.
hobbs
(y no, no estoy contando saycomo parte del código, es solo para fines ilustrativos)
hobbs
1
Si elimina mysin use strict, $nes 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í.
Chris
2

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 0como 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:

(      )  -- push the following value:
 {  }     --   while ToS ≠ 0 (sums the runs):
  {}      --     pop 1 element
     {}   --   pop the remaining 0 & add it

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 -rbandera, 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
Oh Dios mío ... ¡Genial!
Eugene D. Gubenkov
2

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í .

#define r union r
t=0;r{int v;r(*f)();};r e;r f(a){t+=a;e.v=a?f:t;t*=a>0;return e;}

El valor terminal es cero. El valor de retorno es una unión, por lo que para llamar al resultado, use el campo fy para acceder al valor final, use el campo v, por ejemplo

f(1).f(2).f(3).f(0).v

Prué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 fse almacena en la unión devuelta a través del intmiembro, 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!

Jakob
fuente
2

APL (Dyalog Classic) , 48 47 46 44 32 bytes

r←(a f)x
r←⍎'(a+x)f'↓⍨-0=x

0f

Prué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!

Zacharý
fuente
si se puede usar 0 como valor de terminación, el cambio :If x<0a :If×xe intercambiar los "si" y "cláusulas else"
NGN
Derp. No vi que decía "no positivo"
Zacharý
conoces este truco? r←⍎condition⊃'else' 'then'
ngn
32 bytes
NGN
Pensé que decía 22 ...> _ <
Zacharý
1

Perl 6 , 31 bytes

sub f(\n){->$m?{$m??f n+$m!!n}}
Sean
fuente
1

Dyvil , 34 bytes

infix int apply(i:int,j:int=0)=i+j

Uso :

0() // = 0
0(1)() // = 1
0(1)(2)() // = 3

El final ()puede ser omitido.

Explicacion :

Define un operador de yuxtaposición que toma dos entradas y las agrega. El parámetro jtiene el valor predeterminado 0para admitir la llamada sin argumentos. El 0en los ejemplos anteriores no es el nombre, sino un literal.

Choque suave
fuente
1

Julia v0.5 +, 52 bytes

type F n end
F()=0
(f::F)()=f.n
(f::F)(x)=(f.n+=x;f)

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.

Julian Wolf
fuente
1

R, 40 bytes

f=function(x)function(y)`if`(y,f(x+y),x)

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 :

f=x->(y->`if`(y,f(x+y),x))

(Sí, eso es válido R. Solo necesita una importación).

Konrad Rudolph
fuente
1

PHP, 44 bytes

Una idea de @ user63956

Llamada de terminación 0

function f($i){return[$_GET[0]+=$i][$i]?:f;}

Versión en línea

Llamada de terminación con NULLnecesidad de un càst [$i]para[+$i]

PHP, 47 bytes

function f($i){global$s;return$i?f.!$s+=$i:$s;}

Versión en línea

PHP, 52 bytes

Llamada de terminación NULLo cualquier otro valor que sea falso en PHP

function f($i){global$s;$i?$s+=$i:print$s;return f;}

si el programa debe finalizar después de que la salida se reemplace print$scon die("$s")+ 2 bytes

Versión en línea

Jörg Hülsermann
fuente
1
Creo que la función debería volver (no imprimir) $s. para que pudieras hacer algo como return$i?f:$sal final
Conor O'Brien
@ ConorO'Brien No estoy seguro, pero si su pensamiento es correcto, podría ahorrar 5 Bytes Gracias
Jörg Hülsermann
1
Unos pocos bytes se pueden guardar con variables superglobales: function f($i){return[$_GET[0]+=$i][$i]?:f;}.
user63956
@ user63956 una muy buena idea
Jörg Hülsermann
1

PowerShell, 86 bytes

$f={$n=$args[0];$f=(gv f).value;{if($args){&$f($args[0]+$n)}else{$n}}.getnewclosure()}

Pruébalo en línea!

Código de prueba:

&(&(&(&(&(&$f 4)2)7)5)2)

Salida: 20

Andrei Odegov
fuente
Muy agradable. Bienvenido a PPCG! Puede guardar un byte haciendo en $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.
AdmBorkBork
1

Python, 69 bytes

def f(a=0,s=[]):
    if a:
        return lambda b=0:f(b,s+[a])
    return sum(s)
Zhengqun Koo
fuente
1
¿Asumo que esto es python? Debe indicar el idioma utilizado en su respuesta.
corvus_192
¿Puedes intentar jugar más tu respuesta? Tal como está, no está muy bien golfizado.
Rɪᴋᴇʀ
1

Octava, 39 bytes

function r=f(n)r=@(m)merge(m,f(m+n),n);

* El argumento de la llamada de terminación es 0.

Pruébalo en línea!

* endfunctionrequerido para agregar algunos otros códigos.

rahnema1
fuente
1

R, 54 52 bytes

f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}

¡Ahorré 2 bytes gracias a MickyT!

Similar a una de las respuestas de Python. Sin golf:

f=function(x){
  g=function(y=''){
    if(y>''){
      f(y+x)
      }
      else{x}
  }
  g
}

Corre como

> f(1)(2)(4)()
[1] 7
BLT
fuente
1
Buen trabajo. Puede deshacerse de las llaves internas alrededor de la cláusula if. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT
Estoy un poco desconcertado por qué tiene su versión "no golfista" return. returnen R no es lo mismo que en otros idiomas, realiza un aborto prematuro. No usar returnes idiomático. Por otro lado, su versión sin golf todavía tiene el golf if.
Konrad Rudolph el
@KonradRudolph El golf iffue pereza, pero returnes solo por legibilidad: da el mismo resultado con o sin return.
BLT
@BLT Hm. Creo firmemente que la R gratuita return disminuye la legibilidad porque señala algo incorrecto (salida prematura) y es una instancia de programación de culto de carga .
Konrad Rudolph el
Genial, aprendí algo nuevo otra vez. Esa es una razón por la que sigo volviendo. Gracias @KonradRudolph, también esta pregunta de Stack Overflow es interesante: stackoverflow.com/questions/11738823/…
BLT