Curry di lunghezza arbitraria


53

Scrivi una funzione, fche accetta un numero intero positivo e restituisce una funzione.

La nuova funzione restituita dovrebbe essere identica a f. Tuttavia, quando si verifica la "chiamata di terminazione", fdovrebbe invece restituire la somma di tutti i numeri interi passati.

Ad esempio, g=f(4)(se fè la prima funzione) dovrebbe essere impostato gsu un'altra funzione. h=g(3)farà lo stesso. Tuttavia, quando si chiama hsenza argomenti (vedere di seguito per i dettagli), dovrebbe essere visualizzato 7, poiché questa è la somma degli argomenti della funzione precedente. In altre parole, f(3)(4)() == 7.

Si noti che questo non è lo stesso di f(3,4)().

"Termination call" è una delle seguenti opzioni (a scelta):

  • chiama senza argomenti
  • null come argomento
  • qualsiasi valore non positivo

È necessario supportare un numero arbitrario di chiamate di funzione, non esiste un limite predefinito.

È garantito che la somma totale non sarà maggiore di 1'000.

Possiamo presumere che sia stata effettuata almeno una chiamata prima della "chiamata di terminazione".

Il tuo codice non dovrebbe usare variabili statiche per programma, quindi dovrebbe essere possibile eseguire l'esperimento più volte nello stesso runtime e osservare esattamente lo stesso comportamento.

Esempi:

f(1)() == 1
f(4)(2)(7)() == 13
f(4)(2)(7)(5)(2)() == 20

4
@LuisMendo In genere significa che f(4)restituisce una nuova funzione. Se quella nuova funzione viene chiamata senza argomenti, restituisce 4, ma se viene chiamata con un altro argomento, restituirà nuovamente una nuova funzione con la stessa semantica ma con il nuovo argomento aggiunto a 4e così via.
Martin Ender,

6
@LuisMendo Dipende davvero da Eugene, ma penso che consentire chiamate ripetute porterebbe in modo significativo la sfida, perché la parte interessante non è quella di fare una funzione stateful ma di fare una funzione di ordine superiore.
Martin Ender,

6
@MartinEnder Questo ha molto senso. Eugene, se questo è l'intento, per favore cambia la formulazione della sfida. Scrivere una funzione che può essere chiamata all'infinito non suggerisce affatto che la funzione dovrebbe restituire una funzione
Luis Mendo,

4
Possiamo presumere che ci sarà solo un'istanza della catena di chiamate alla volta? Ad esempio no q = f(2)(3); b = f(1)(2)(3); q(); b()?
Conor O'Brien,

3
Avendo appena raccolto Haskell, mi interessa sapere se questo è possibile a Haskell. Il forte sistema di tipi mi fa pensare che potrebbe non esserlo.
CAD97

Risposte:


49

JavaScript (ES6), 18 byte

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

Passa un valore falso per recuperare la somma. Gli zeri potrebbero essere consentiti per un costo di 2 byte.

Provalo online

Ungolfed:

f = function(n) {
    return function(m) {
        if (m) {
            return f(m+n);
        } else {
            return n;
        }
    }
}

Presentazione brillante!
Eugene D. Gubenkov,

21

Haskell (GHC), 118 byte

Si tratta di 98 byte per il codice e 20 byte per il flag del compilatore GHC -XFlexibleInstances, che consente un'estensione di sistema del tipo.

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

Questo definisce una "funzione" f, che può essere chiamata con un numero arbitrario di numeri interi seguiti dall'unità (), dopo di che restituisce un numero intero. Sono necessarie annotazioni di tipo. Provalo online!

Spiegazione

Forzare il rigido sistema di tipi di Haskell per consentire ciò richiede un po 'di magia, vale a dire abilitare l'estensione GHC per istanze di classe di tipo flessibile. Come funziona è funa funzione parametricamente polimorfica limitata da un vincolo di classe di tipo: il suo tipo è F a => Int -> a. Ciò significa che faccetta un numero intero e restituisce un valore di tipo a, per qualsiasi tipo aappartenente alla typeclass F. Fè solo il nome della typeclass che fornisce la funzione f; è dichiarato sulla prima riga.

Le due righe successive sono due istanze di Fper tipi diversi a. La seconda riga afferma che ()appartiene il tipo di funzioni da a numeri interi F(dove ()è il tipo di unità il cui unico membro è il valore ()) e l'implementazione è f n () = n; la funzione restituisce il suo primo argomento. L'ultima riga afferma che se aappartiene F, quindi fa anche il tipo di funzioni da numeri interi a a: da una funzione f :: Int -> apossiamo generare un'altra funzione f :: Int -> Int -> a. L'implementazione è f m n = f (m+n)(il codice usa i combinatori per renderlo più breve), dove fa sinistra è quello nuovo e fa destra è quello vecchio. Questo essenzialmente dàfun nuovo argomento intero, che viene aggiunto a quello successivo. Più argomenti sono riassunti insieme in questo modo:

  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

Il fsu ogni riga ha un tipo diverso.

Le funzioni di Haskell vengono automaticamente modificate, quindi se si danno fsolo numeri interi, si ottiene una funzione.


1
Forse sto scherzando, ma non è proprio quello che la sfida richiede. Stai definendo due (!) Funzioni, entrambe chiamate f, non una singola funzione che fa il lavoro. Tuttavia, questo è il più vicino possibile a Haskell. Non penso che sia possibile risolvere l'attività con un'unica funzione a causa del sistema di tipi rigoroso.
nimi,

3
@nimi Questo definisce non due funzioni chiamate f, ma infinitamente molte funzioni chiamate f. (Una per ogni possibile numero di argomenti.) Queste funzioni (da questa famiglia infinita) hanno due tipi di definizioni, una sorta quando il numero di argomenti è zero e un'altra quando non lo è.
ShreevatsaR

@ShreevatsaR: vedo due definizioni f n()=ne f=(f.).(+)quindi la definirei definendo due funzioni.
nimi,

7
@nimi Ci sono due definizioni, ma non due funzioni. Il numero di definizioni non deve necessariamente essere il numero di funzioni. Ad esempio, è possibile definire la funzione fattoriale con le due definizioni g 0 = 1e g n = g (n-1) * n, dove sono presenti due definizioni ma solo una funzione. Qui abbiamo due definizioni ma infinitamente molte funzioni. (Ognuno di un tipo diverso.)
ShreevatsaR

1
@nimi BTW nel ghcicaricare quanto sopra e provare :t f- dirà f :: F a => Int -> a(nel senso che se aè un'istanza di classe f, allora fè una funzione Int -> a). Quindi potremmo considerare questa come una funzione o infinitamente molte, ma sebbene abbia due tipi di definizioni (proprio come la funzione fattoriale) non vedo alcuna buona base per considerarla come due funzioni.
ShreevatsaR

15

Python 2, 42 41 36 byte

Questa soluzione non avrà mai un overflow, poiché Python supporta numeri interi di precisione arbitraria. Zero è il "valore speciale".

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

Provalo online

Ungolfed:

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

14

C, 62 58 byte, borderline in competizione

Salvato 4 byte grazie a Kevin! (Continuando a non rimuovere typedef perché è necessario per essere chiamato.)

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

La funzione da chiamare è f; smetti di chiamarlo e ottieni il risultato chiamandolo con un numero non positivo come 0. Prova un cablaggio di prova online!

Quindi, per quanto posso dire, l'unico modo per "curry" funzioni che hanno più tipi di ritorno è di effettuare una delle seguenti operazioni:

  1. Trasmetti il ​​risultato a una funzione per dire al compilatore che desideri richiamare di nuovo il risultato;
  2. oppure creare un tipo union/ structche abbia un intsottotipo e funzione / autoreferenziale.

Ho provato a fare (2), ma mi è sembrato un po 'contrario allo spirito della domanda e, francamente, quasi inevitabile. Pertanto, in linea con lo spirito della sfida, ho optato per l'opzione (1). Ciò richiede il cast di ciascuna funzione restituita in una funzione, che può essere utilizzata.

Questa sintassi "curry" sembra un po 'strana, ma è abbastanza simile. Per emulare f(21)(1), si dovrebbe scrivere ((B)((B)f(21))(1))(0). Ho definito il Btipo come una funzione che accetta un numero intero e restituisce un puntatore a una funzione che accetta un numero intero. Espanso, questo assomiglia a:

   ( (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

Se dici che termina solo con 0, avrai bisogno del casting (cosa che fai in C perché C non può definire correttamente una funzione che ritorna se stessa) e lasci azzerando il globale tra le esecuzioni verso il chiamante (che Penso che sia perfettamente ragionevole), puoi semplificare il tutto q;f(x){return x?(q+=x,f):q;}.
Kevin,


1
@Kevin, secondo le regole del sito, una funzione deve essere riutilizzabile. Se non eseguissi l'azzeramento qdopo ogni corsa, la funzione non sarebbe più utilizzabile
Conor O'Brien,

Forse i puntatori a funzione? Dovresti fare riferimento ogni volta, ma potrebbe valere la pena dare un'occhiata
Downgoat,

1
@ ConorO'Brien Ho appena implementato il tuo approccio sindacale. È più lungo di questo, ma non è lontano.
Jakob,

13

Mathematica, 25 byte

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

Provalo online! (Usando la matematica.)

È possibile fare tre byte in meno eseguendo il porting della risposta JavaScript, ma volevo presentare una soluzione Mathematica più idiomatica. Il @è solo un po 'di zucchero sintattico, il che rende la soluzione equivalente a:

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

Quindi sì, l'idea è che in Mathematica non si può semplicemente definire una funzione f[x_]ma è possibile associare direttamente un valore a un'espressione più complicata contenente f, ad esempio, il f[x_]passaggio di un altro argomento. Impostando due definizioni per questo, possiamo ottenere il comportamento desiderato:

  • La prima definizione comprime una f[x][y]chiamata f[x+y], consumando così una "chiamata" e sommando gli argomenti all'interno. Questa regola si applica fino a quando non ci resterà f[sum][].
  • La seconda definizione disimballa questo caso finale definendo l'intero oggetto da valutare sum.

1
<3 programmazione simbolica
Julian Wolf,

8

C ++, 72 byte

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

Questo definisce un tipo Fche funge da funzione richiesta e una variabile fdi quel tipo da invocare. È valido a partire da C ++ 11 e funziona con le versioni online di GCC, clang, icc e VC ++.

Uso:

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

Spiegazione:

Dopo la preelaborazione e la riformattazione, sembra che:

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

Questo sarebbe normalmente scritto:

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

return a;e return {+a};fare la stessa cosa, in quanto unario +non modifica il valore e sono consentite parentesi graffe ridondanti attorno al valore restituito. int me int(m)fare la stessa cosa, poiché sono consentite parentesi ridondanti attorno a un nome di variabile, inclusi i parametri di funzione. return {m+a};e return {int(m)+a};fare la stessa cosa, poiché un cast di mda inta intnon cambia il suo valore. Queste modifiche avvicinano i due operator()sovraccarichi nella sintassi, consentendo di invocare due volte una singola definizione di macro. Scegliere l'ordine giusto per i tre membri consente di intincludere anche la prima parola della riga successiva ( ) nella definizione macro.


1
Bellissimo. E non solo la soluzione golfizzata ... sovraccaricare operator()per rendere questo lavoro particolarmente interessante.
Ray Toal,

6

Rubino, 23 byte

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

Uso:

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

6

C, 104 96 byte

#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;}

Utilizza il metodo dal collegamento condiviso da @JulianWolf. L'ultimo argomento deve essere 0.

Provalo online!


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Dennis,

4

Math.JS, 38 byte

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

Chiamalo con f(number_a)(number_b)(...)(negative_number)

Se è consentito specificare la chiamata iniziale, è possibile eliminare 12 byte ( f(x)=i(x,0)\n) e può essere chiamato coni(number_one,0)(number_two)(...)(negative_number)

Provalo!

explination

LaTeX!

Come mostrato in LaTex sopra, f(x)semplicemente chiama i(x,0), quindi, i(x,y)restituisce il valore di yif xè minore di 0, o la funzione j(z)=i(z,x+y), che accetta un argomento, che esegue il loop. Aggiungendo al valore di y.


4

C, 232 206 byte

#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;}

Questo può probabilmente essere giocato a golf in modo significativo, ma dovrebbe servire come una prova del concetto che C può essere usato, senza estensioni del linguaggio *, per risolvere questo problema chiamando senza argomenti piuttosto che con un valore magico.

* @hvd ha notato che, mentre questo funziona in modo predefinito usando gcc, alcuni comportamenti non sono definiti nello standard C, il che significa che potrebbe non essere portatile. Utilizzare a proprio rischio!

Ungolfed:

#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;
}

Compilazione e funzionamento con gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingoutput (dopo alcuni avvisi)

f(1)()          -> 1
f(1)(2)(3)(0)() -> 6
f(1)(-2)(3)()   -> 2
f()             -> 0

"senza estensioni del linguaggio" - Il trucco di alternare tra ge hcontinuare una catena di macro invocazioni non è garantito per funzionare, in quanto non è specificato se il prossimo gappare nel contesto dell'espansione del primo g. C11 aggiunge un esempio a 6.10.3.4 per precisare che non è specificato. (IIRC, il preprocessore di TenDRA è uno che non lo espanderebbe nel modo desiderato). A parte ciò, nessuna versione del linguaggio supporta sia argomenti macro vuoti che int impliciti, quindi un programma C valido non può usare entrambi. :) Comunque, bella risposta. Stai cercando di giocare a golf?
hvd,

@hvd: sì, probabilmente ci tornerò tra un paio di giorni e vedrò se posso giocare a golf. Hai assolutamente ragione sul fatto che si tratta di un comportamento non specificato, ma penso che il trattamento standard qui sia che le lingue siano definite dalla loro implementazione, quindi finché funziona con gcc sono contento.
Julian Wolf,

Stavo solo affrontando il commento che hai inserito nella tua risposta che non si basa su alcuna estensione di lingua. Sì, anche con le estensioni di lingua, è perfettamente valido come risposta qui, non intendeva suggerire diversamente.
hvd,

Ah, è decisamente giusto. Hai ragione sul fatto che dovrei stipulare che, sebbene non siano richieste bandiere extra, questo potrebbe non essere portatile.
Julian Wolf,

È possibile verificare la stringa vuota con *sanziché strlen(s). Le stringhe C hanno una lunghezza implicita, terminata da un charvalore 0. Bello macro hack per consentire la chiamata con / senza arg!
Peter Cordes,

4

8086 codice macchina, 27 byte

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

Questo codice macchina deve essere all'indirizzo 0x100 e assume il modello di codice minuscolo (cs = ds = es = ss). Tuttavia, la posizione della funzione può essere modificata senza costare byte extra. Mettendolo in offset 0si salverebbe un byte ( xor si,siinvece di mov si, 0x100)

Convenzione di chiamata obbligatoria

Ciò presuppone che il chiamante abbia pre-allocato almeno 27 byte nello stack. Accetta un numero axe restituisce un puntatore a funzione bx. Chiamare questo puntatore con ax=0termina la catena e restituisce la somma in bx.
Quindi per la prima chiamata:

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

Quindi, per ogni chiamata successiva:

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

Terminare:

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

Ungolfed (disassemblaggio commentato del codice macchina):

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

Dopo averlo chiamato con AX diverso da zero, bx = spil buffer viene riempito con una copia modificata del codice macchina da function. Il 16 bit immediato nella prima istruzione contiene il totale. (È scritto dall'ultima istruzione prima del ret.)

push di/ pop bxpotrebbe essere sostituito con mov bx, di(prima rep movsb), rendendolo più semplice ma senza risparmi.

Richiedere al chiamante di passare un puntatore al buffer dst in per disalvare 4 byte rispetto al calcolo relativo sp.

Rendere l'indirizzo di inizio della funzione uguale alla dimensione della funzione salverebbe un byte ( mov cx, si).


Questa sarebbe una risposta migliore se si includesse lo smontaggio dei byte del codice macchina. le risposte in codice macchina hanno sicuramente bisogno di una versione non controllata. es. usare al objdump -b binaryposto dihexdump -C
Peter Cordes

Aggiornato con lo smontaggio commentato. Possibili risparmi: richiedere al chiamante di passare un puntatore dst in di(4 byte). Rendi la funzione start address = size: mov cx, sianziché mov cx, 0x1b.
Peter Cordes,

2

C #, 62 byte

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

Per terminare la chiamata, passare un numero negativo, ad es

f(1)(2)(3)(-1) == 6

Mi piacerebbe farlo funzionare passando nullo nessun parametro alla fine. Tuttavia, tutti i modi in cui ho provato sono stati molto più lunghi
TheLethalCoder

Puoi usare !minvece di m<0e passare nullo 0come ultimo parametro?
Betseg,

@betseg No in C # solo un Booleanpuò essere usato come Boolean... Ho provato con nullma è diventato più lungo. Volevo usare il ??che significa che se LHS è null fare RHS, ma come ho bisogno se LHS non è null fare questo altrimenti fare RHS non potrei.
TheLethalCoder

2

Scala, 58 caratteri

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

Provalo online

Ungolfed:

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

Spiegazione:

Questo codice definisce una case classchiamata f con un costruttore che prende un int. Definire una classe case che genererà i metodi equals, hashcode, toString e copy e un oggetto associato con lo stesso nome per abilitare la creazione di oggetti senza la newparola chiave.

Questa classe ha un metodo di applicazione sovraccarico: uno prende un altro numero intero per aggiungere e crea un nuovo oggetto con la somma aggiornata e uno senza argomenti per ottenere la somma.

In Scala, qualsiasi oggetto con un metodo apply può essere chiamato come un metodo, ovvero o.apply(x)può essere scritto come o(x). Viene utilizzato nella libreria standard per matrici, elenchi, mappe e Function1tratti implementati da funzioni anonime


2

Pyth, 19 byte

DhdDebR?bh+dbdR$end

Provalo online!

Sono impressionato dal fatto che Javascript superi Pyth, ma poi Pyth non è del tutto progettato per passare funzioni.


2

Perl 5, 36 byte

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

say f(1)->(); # 1
say f(1)->(2)->(3)->(); # 6

Che cosa richiede questo -M5.016? Sembra che dovresti essere in grado di rilasciare -M5.016e quindi rilasciare mye salvare un paio di byte. Se è solo say, puoi usare -Einvece il flag , che non si attiva use strict, quindi puoi ancora rilasciare il my.
Chris,

@Chris hai ragione, non ha bisogno della 5.16, la mia revisione iniziale ha fatto (usando __SUB__) ma l'ho cambiata prima di inviare e non ho rimosso il bit su 5.16. Lo toglierò. Non credo che cadere mysarebbe corretto però.
Hobbs

(e no, non conto saycome parte del codice, è solo a scopo illustrativo)
hobbs

1
Se rimuovi mysenza use strict, $nè implicitamente una variabile globale. È una cattiva forma negli script perl corretti, ma è piuttosto comune in una riga, e sembra funzionare qui.
Chris,

2

Brain-Flak , 6 byte

In realtà ho appena notato che poiché il ToS è un formato di ritorno valido che fa scoppiare lo 0 non è davvero necessario che consente di risparmiare 2 byte:

({{}})

Provalo online!

Presentazione / i originale / i, 8 byte

Utilizza 0come valore speciale:

({{}}{})

Provalo online!

Spiegazione

Dati gli argomenti a 1 , a 2 ,…, a n , 0 lo stack inizialmente assomiglia a questo:

                                                       a n

                                                       

                                                       a 2

                                                       a 1

                                                       0

Il codice passa poi, si apre ogni uno ho , li accumula, si apre il 0 li aggiunge e spinge il risultato:

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

Soluzioni alternative, 8 byte

Invece di schioccare lo 0 e aggiungerlo alla somma, possiamo anche scambiare pile poiché quella giusta è inizialmente vuota:

({{}}<>)

Provalo online!

Usando il -rflag lo 0 è in cima allo stack, quindi potremmo prima pop:

({}{{}})

Provalo online!

{}({{}})

Provalo online!


Oh mio Dio ... Fantastico!
Eugene D. Gubenkov,

2

C (GCC), 83 byte

Il mio primo golf C! Ci sono un paio di altre soluzioni C, ma questa è un po 'diversa. L'uso del preprocessore è puramente cosmetico. Questo approccio è stato discusso per la prima volta nella risposta di Conor O'Brien qui .

#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;}

Il valore del terminale è zero. Il valore restituito è un unione, quindi per chiamare il risultato, utilizzare il campo fe per accedere al valore finale, utilizzare il campo v, ad es

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

Provalo online

limitazioni

Una variabile globale contiene il totale parziale. Sebbene ciò sia esplicitamente vietato, l'invio supporta ripetute invocazioni (il totale viene ripristinato nella chiamata terminale), che sembra essere il motivo del divieto di stato globale.

Un puntatore a fviene memorizzato nell'unione restituita tramite il intmembro, quindi chiaramente non è portatile. Non sono sicuro che funzioni su GCC su tutte le piattaforme o solo su Linux o solo su x86 o solo con ELF o ... Se qualcuno conosce qualche dettaglio a riguardo, si prega di commentare o inviare un messaggio!


2

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

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

0f

Provalo online!

Termina passando a zero. Sintassi della chiamata:((0 f 1) 2) 0

-15 byte grazie a @ngn

Richiede ⎕IO←0

Tutti i suggerimenti per il golf sono i benvenuti!


se è possibile utilizzare 0 come valore di terminazione, il cambiamento :If x<0per :If×xe scambiare i "se" e clausole di "else"
NGN

Derp. Non ho visto che dicesse "non positivo"
Zacharý

conosci questo trucco? r←⍎condition⊃'else' 'then'
ngn


Pensato che dicesse 22 ...> _ <
Zacharý


1

Dyvil , 34 byte

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

Utilizzo :

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

Il trailing ()può essere omesso.

Spiegazione :

Definisce un operatore di giustapposizione che accetta due ints e li aggiunge. Il parametro jha il valore predefinito 0per supportare la chiamata senza argomenti. L' 0esempio sopra non è il nome, ma letterale.


1

Julia v0.5 +, 52 byte

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

Chiama come F. Probabilmente questo potrebbe essere molto più breve adottando un metodo meno OO, ma mi piace sempre avere la possibilità di usare questo linguaggio.

Se si può presumere che "verrà effettuata almeno una chiamata prima della chiamata di terminazione", è possibile rimuovere la seconda linea per salvare 6 byte.



1

R, 40 byte

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

0 funge da valore di arresto qui. Per altri due byte, possiamo ometterlo.

Il problema è che R manca di un lambda incorporato conciso. Ma se ne aggiungiamo uno , possiamo ottenere il codice a 26 byte :

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

(Sì, è valido R. Ha solo bisogno di un'importazione.)


1

PHP, 44 byte

Un'idea di @ user63956

Chiamata di terminazione 0

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

Versione online

Chiamata di terminazione con NULLnecessità di càst [$i]a[+$i]

PHP, 47 byte

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

Versione online

PHP, 52 byte

Chiamata di terminazione NULLo qualsiasi altro valore falso in PHP

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

se il programma deve terminare dopo l'uscita sostituire print$scon die("$s")+ 2 byte

Versione online


1
Penso che la funzione dovrebbe tornare (non stampare) $s. così si potrebbe fare qualcosa di simile return$i?f:$salla fine
Conor O'Brien

@ ConorO'Brien Non ne sono sicuro, ma se il tuo pensiero è corretto, potresti risparmiare 5 byte Grazie
Jörg Hülsermann,

1
A pochi byte possono essere salvati con le variabili superglobali: function f($i){return[$_GET[0]+=$i][$i]?:f;}.
user63956

@utente63956 un'idea molto bella
Jörg Hülsermann

1

PowerShell, 86 byte

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

Provalo online!

Codice di prova:

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

Uscita: 20


Molto bella. Benvenuti in PPCG! È possibile salvare un byte facendo $n="$args"invece di $n=$args[0]. Non funzionerà sull'altro $args[0], però, perché in questo caso otterrai concatenazione di stringhe anziché aggiunta.
AdmBorkBork,


1

Python, 69 byte

def f(a=0,s=[]):
    if a:
        return lambda b=0:f(b,s+[a])
    return sum(s)

1
Suppongo che questo sia Python? Dovresti indicare la lingua usata nella tua risposta.
corvus_192,

Puoi provare a golf la tua risposta di più? Allo stato attuale, non è molto ben golfato.
Rɪᴋᴇʀ

1

Ottava, 39 byte

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

* L'argomento della chiamata di terminazione è 0.

Provalo online!

* endfunctionrichiesto per aggiungere altri codici.


1

R, 54 52 byte

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

Salvato 2 byte grazie a MickyT!

Simile a una delle risposte di Python. Ungolfed:

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

Funziona come

> f(1)(2)(4)()
[1] 7

1
Bel lavoro. È possibile eliminare le parentesi graffe interne attorno alla clausola if. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT

Sono un po 'perplesso sul perché la tua versione "non rigata" lo sia return. returnin R non è lo stesso di altre lingue, esegue una interruzione prematura. Non usando returnè idiomatica. D'altra parte la tua versione non golfata ha ancora il golf if.
Konrad Rudolph,

@KonradRudolph Il golf ifera pigrizia, ma returnè solo per leggibilità - dà lo stesso risultato con o senza return.
BLT,

@BLT Hm. Sento fortemente che gratuito in R return diminuisce la leggibilità perché segnala la cosa sbagliata (uscita prematura) ed è un esempio di programmazione di culto del carico .
Konrad Rudolph,

Bene, ho imparato di nuovo qualcosa di nuovo. Questa è una ragione per cui continuo a tornare. Grazie @KonradRudolph, anche questa domanda Stack Overflow è interessante: stackoverflow.com/questions/11738823/…
BLT

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.