Beliebig langes Currying


53

Schreiben Sie eine Funktion, fdie eine positive Ganzzahl aufnimmt und eine Funktion zurückgibt.

Die zurückgegebene neue Funktion sollte mit identisch sein f. Wenn jedoch der "Beendigungsaufruf" auftritt, fsollte stattdessen die Summe aller übergebenen Ganzzahlen zurückgegeben werden.

Zum Beispiel sollte g=f(4)(wenn fist die erste Funktion) auf geine andere Funktion eingestellt werden. h=g(3)werde das gleiche tun. Wenn Sie jedoch hkeine Argumente aufrufen (siehe unten für Details), sollte 7 ausgegeben werden, da dies die Summe der vorherigen Funktionsargumente ist. Anders ausgedrückt f(3)(4)() == 7.

Beachten Sie, dass dies nicht dasselbe ist wie f(3,4)().

"Terminierungsanruf" ist eine der folgenden Optionen (Ihre Wahl):

  • Aufruf ohne Argumente
  • Null als Argument
  • ein nicht positiver Wert

Beliebig viele Funktionsaufrufe sollen unterstützt werden, es gibt kein vordefiniertes Limit.

Es ist garantiert, dass die Gesamtsumme nicht größer als 1'000 sein wird.

Wir können davon ausgehen, dass vor dem "Terminierungsanruf" mindestens ein Anruf getätigt wird.

In Ihrem Code sollten keine statischen programmspezifischen Variablen verwendet werden. Daher sollte es möglich sein, das Experiment mehrere Male in derselben Laufzeit auszuführen und genau dasselbe Verhalten zu beobachten.

Beispiele:

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

4
@ LuisMendo Es bedeutet im Allgemeinen, dass f(4)eine neue Funktion zurückgegeben wird. Wenn diese neue Funktion ohne Argumente aufgerufen wird, wird sie zurückgegeben 4. Wenn sie jedoch mit einem anderen Argument aufgerufen wird, wird erneut eine neue Funktion mit der gleichen Semantik zurückgegeben, jedoch mit dem neuen Argument, das dem 4usw. hinzugefügt wurde .
Martin Ender

6
@ LuisMendo Es liegt in der Tat an Eugene, aber ich denke, dass das Zulassen von wiederholten Anrufen die Herausforderung erheblich verringern würde, da der interessante Teil nicht darin besteht, eine stateful-Funktion zu erstellen, sondern eine Funktion höherer Ordnung.
Martin Ender

6
@ MartinEnder Das macht sehr viel Sinn. Eugene, wenn das die Absicht ist, ändern Sie bitte den Wortlaut der Herausforderung. Schreiben Sie eine Funktion, die unendlich aufgerufen werden kann, bedeutet nicht, dass die Funktion eine Funktion zurückgeben soll
Luis Mendo

4
Können wir davon ausgehen, dass es jeweils nur eine Instanz der Aufrufkette gibt? ZB nein q = f(2)(3); b = f(1)(2)(3); q(); b()?
Conor O'Brien

3
Ich habe gerade Haskell abgeholt und bin daran interessiert, ob dies in Haskell möglich ist. Das starke Typensystem lässt mich denken, dass es nicht sein könnte.
CAD97

Antworten:


49

JavaScript (ES6), 18 Byte

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

Übergeben Sie einen falschen Wert, um die Summe abzurufen. Nullen können für 2 Byte zugelassen werden.

Probieren Sie es online aus

Ungolfed:

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

Geniale Vorlage!
Eugene D. Gubenkov

21

Haskell (GHC), 118 Bytes

Dies sind 98 Byte für den Code und 20 Byte für das GHC-Compiler-Flag -XFlexibleInstances, das eine Typsystemerweiterung ermöglicht.

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

Dies definiert eine "Funktion" f, die mit einer beliebigen Anzahl von Ganzzahlen aufgerufen werden kann, gefolgt von der Einheit (), nach der eine Ganzzahl zurückgegeben wird. Typanmerkungen sind erforderlich. Probieren Sie es online!

Erläuterung

Damit das strenge Typensystem von Haskell dies zulässt, ist ein gewisses Maß an Magie erforderlich, nämlich die Aktivierung der GHC-Erweiterung für flexible Typklasseninstanzen. Wie dies funktioniert, fist eine parametrisch polymorphe Funktion, die durch eine Typklassenbeschränkung eingeschränkt ist: ihr Typ ist F a => Int -> a. Dies bedeutet, dass für jeden Typ , der zur Typenklasse gehört, feine Ganzzahl verwendet und ein Wert vom Typ zurückgegeben awird . ist nur der Name der Typklasse, die die Funktion bereitstellt ; Es ist in der ersten Zeile deklariert.aFFf

Die nächsten beiden Zeilen sind zwei Instanzen von Ffür verschiedene Typen a. Die zweite Zeile gibt an, dass der Typ der Funktionen von ()bis zu ganzen Zahlen gehört F(wobei ()der Einheitentyp ist, dessen einziges Element der Wert ist ()), und die Implementierung ist f n () = n; Die Funktion gibt ihr erstes Argument zurück. Die letzte Zeile besagt, dass, wenn zu agehört F, auch die Art der Funktionen von Ganzzahlen zu a: von einer Funktion können f :: Int -> awir eine andere Funktion generieren f :: Int -> Int -> a. Die Implementierung ist f m n = f (m+n)(der Code verwendet Kombinatoren, um sie zu verkürzen), wobei flinks die neue und frechts die alte ist. Dies gibt im Wesentlichenfein neues ganzzahliges Argument, das dem nächsten hinzugefügt wird. Mehrere Argumente werden folgendermaßen zusammengefasst:

  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

Die fin jeder Zeile hat einen anderen Typ.

Haskell-Funktionen werden automatisch aufgerufen. Wenn Sie also fnur Ganzzahlen angeben, erhalten Sie eine Funktion.


1
Vielleicht nicke ich, aber es ist nicht ganz das, wonach die Herausforderung verlangt. Sie definieren zwei (!) Funktionen, die beide aufgerufen werden f, und keine einzige Funktion, die die Aufgabe erfüllt. Dies ist jedoch so nah wie Sie in Haskell bekommen können. Ich denke nicht, dass es möglich ist, die Aufgabe mit einer einzigen Funktion zu lösen, da das Typensystem streng ist.
nimi

3
@nimi Definiert nicht zwei aufgerufene Funktionen f, sondern unendlich viele aufgerufene Funktionen f. (Eine für jede mögliche Anzahl von Argumenten.) Diese Funktionen (aus dieser unendlichen Familie) haben zwei Arten von Definitionen, eine Sortierung, wenn die Anzahl der Argumente Null ist, und eine andere, wenn sie nicht ist.
ShreevatsaR

@ShreevatsaR: Ich sehe zwei Definitionen f n()=nund f=(f.).(+)nenne es zwei definierende Funktionen.
Nimi

7
@nimi Es gibt zwei Definitionen, aber keine zwei Funktionen. Die Anzahl der Definitionen muss nicht die Anzahl der Funktionen sein. Beispielsweise können Sie die Fakultätsfunktion mit den beiden Definitionen g 0 = 1und definieren g n = g (n-1) * n, wobei es zwei Definitionen gibt, aber nur eine Funktion. Hier haben wir zwei Definitionen, aber unendlich viele Funktionen. (Jeder von einem anderen Typ.)
ShreevatsaR

1
@nimi BTW in ghcidas obige laden und versuchen :t f- es wird sagen f :: F a => Int -> a(was bedeutet, dass wenn aeine Instanz der Klasse ist f, dann fist eine Funktion Int -> a). Wir könnten dies also entweder als eine Funktion oder als unendlich viele betrachten, aber obwohl es zwei Arten von Definitionen gibt (genau wie die Fakultätsfunktion), sehe ich keine gute Grundlage, um es als zwei Funktionen zu betrachten.
ShreevatsaR

15

Python 2, 42 41 36 Bytes

Diese Lösung wird niemals überlaufen, da Python Ganzzahlen mit willkürlicher Genauigkeit unterstützt. Null ist der "spezielle Wert".

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

Probieren Sie es online aus

Ungolfed:

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

14

C, 62 58 Bytes, Borderline-Konkurrenz

4 Bytes gespart dank Kevin! (Typedef wird immer noch nicht entfernt, da es zum Aufrufen benötigt wird.)

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

Die aufzurufende Funktion ist f; Sie hören auf, es anzurufen, und erhalten das Ergebnis, indem Sie es mit einer nicht positiven Zahl wie aufrufen 0. Probieren Sie ein Testgeschirr online aus!

Soweit ich das beurteilen kann, besteht die einzige Möglichkeit, Funktionen mit mehreren Rückgabetypen zu "curryen", darin, eine der folgenden Aktionen auszuführen:

  1. Wandeln Sie das Ergebnis in eine Funktion um, um dem Compiler mitzuteilen, dass Sie das Ergebnis erneut aufrufen möchten.
  2. Oder erstellen Sie einen union/ struct-Typ mit einem intund -Funktions- / Selbstreferenz-Untertyp.

Ich habe versucht (2) zu tun, aber es schien ein bisschen gegen den Geist der Frage und, ganz offen gesagt, fast unlösbar. Aus diesem Grund habe ich mich im Sinne der Herausforderung für Option (1) entschieden. Dazu muss jede zurückgegebene Funktion in eine Funktion umgewandelt werden, die verwendet werden kann.

Diese "currying" Syntax sieht ein bisschen seltsam aus, ist aber ziemlich ähnlich. Um zu emulieren f(21)(1), müsste man schreiben ((B)((B)f(21))(1))(0). Ich habe den BTyp als eine Funktion definiert, die eine Ganzzahl annimmt und einen Zeiger auf eine Funktion zurückgibt, die eine Ganzzahl annimmt. Erweitert sieht das so aus:

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

Wenn Sie sagen, dass es nur bei 0 endet, müssen Sie das Casting ausführen (was Sie in C ausführen, da C eine Funktion, die sich selbst zurückgibt, nicht ordnungsgemäß definieren kann), und Sie überlassen es dem Aufrufer, die globalen Zwischenläufe zu löschen (welche) Ich halte das für durchaus zumutbar), man kann das Ganze zu vereinfachen q;f(x){return x?(q+=x,f):q;}.
Kevin


1
@ Kevin Gemäß den Site-Regeln muss eine Funktion wiederverwendbar sein. Wenn ich nicht qnach jedem Lauf auf Null gesetzt hätte, wäre die Funktion nicht mehr verwendbar
Conor O'Brien,

Vielleicht Funktionszeiger? Sie müssten jedes Mal de Referenz, aber es könnte sich lohnen, zu überprüfen
Downgoat

1
@ ConorO'Brien Ich habe gerade Ihren Gewerkschaftsansatz umgesetzt . Es ist länger als dieses, aber es ist nicht weit weg.
Jakob,

13

Mathematica, 25 Bytes

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

Probieren Sie es online! (Verwenden von Mathematik.)

Durch Portierung der JavaScript-Antwort können drei Bytes gespart werden, aber ich wollte eine idiomatischere Mathematica-Lösung vorstellen. Das @ist nur ein bisschen syntaktischer Zucker, was die Lösung äquivalent macht zu:

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

Die Idee ist also, dass Sie in Mathematica nicht nur eine Funktion definieren, f[x_]sondern einem komplizierteren Ausdruck f, der z. B. f[x_]ein anderes Argument enthält , direkt einen Wert zuweisen können. Indem wir zwei Definitionen dafür einrichten, können wir das gewünschte Verhalten erhalten:

  • Die erste Definition reduziert einen f[x][y]Aufruf auf f[x+y]einen "Aufruf" und addiert die darin enthaltenen Argumente. Diese Regel gilt, bis wir mit verlassen werden f[sum][].
  • Die zweite Definition packt diesen letzten Fall aus, indem sie das gesamte zu bewertende Objekt definiert sum.

1
<3 symbolische Programmierung
Julian Wolf

8

C ++, 72 Bytes

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

Dies definiert einen Typ, Fder als angeforderte Funktion fungiert, und eine Variable fdieses Typs, die aufgerufen werden soll. Es ist ab C ++ 11 gültig und funktioniert mit Online-Versionen von GCC, Clang, ICC und VC ++.

Verwendungszweck:

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

Erläuterung:

Nach der Vorverarbeitung und Neuformatierung sieht es so aus:

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

Dies würde normalerweise geschrieben werden:

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

return a;und return {+a};das gleiche tun, als einstellige +den Wert nicht ändert, und redundante Klammern um den Rückgabewert erlaubt. int mund int(m)das gleiche tun, wie redundante Klammern um einen Variablennamen erlaubt sind, einschließlich Funktionsparameter. return {m+a};und return {int(m)+a};mache dasselbe, da eine Besetzung von mvon intbis intihren Wert nicht ändert. Diese Änderungen rücken die beiden operator()Überladungen in der Syntax näher zusammen, sodass eine einzelne Makrodefinition zweimal aufgerufen werden kann. Wenn Sie die richtige Reihenfolge für die drei Elemente auswählen, wird auch das erste Wort der nächsten Zeile ( int) in die Makrodefinition aufgenommen.


1
Schön. Und nicht nur die Golf-Lösung ... Überladung operator(), um diese Arbeit zu machen, war besonders cool.
Ray Toal

6

Ruby, 23 Bytes

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

Verwendungszweck:

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

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

Verwendet die Methode aus dem Link, den @JulianWolf freigegeben hat. Das letzte Argument muss 0 sein.

Probieren Sie es online!


Kommentare sind nicht für eine längere Diskussion gedacht. Diese Unterhaltung wurde in den Chat verschoben .
Dennis

4

Math.JS, 38 Bytes

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

Nennen Sie es mit f(number_a)(number_b)(...)(negative_number)

Wenn wir den ersten Aufruf angeben dürfen, können 12 Bytes ( f(x)=i(x,0)\n) verworfen und mit aufgerufen werdeni(number_one,0)(number_two)(...)(negative_number)

Versuch es!

Explination

Latex!

Wie in obigem LaTex gezeigt, f(x)ruft es einfach auf i(x,0)und gibt dann i(x,y)den Wert von yif xkleiner als 0 oder die Funktion zurück j(z)=i(z,x+y), die ein Argument annimmt und die eine Schleife durchläuft. Addieren zum Wert von y.


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

Dies kann wahrscheinlich erheblich verbessert werden, sollte jedoch als Beweis dafür dienen, dass C ohne Spracherweiterungen * verwendet werden kann, um dieses Problem durch Aufrufen ohne Argumente und nicht mit einem magischen Wert zu lösen.

* @hvd hat festgestellt, dass dies zwar mit gcc funktioniert, einige Verhaltensweisen jedoch nicht im C-Standard definiert sind, was bedeutet, dass dies möglicherweise nicht portabel ist. Benutzung auf eigene Gefahr!

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

Kompilieren und Ausführen mit gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingAusgaben (nach einigen Warnungen)

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

"Ohne Spracherweiterungen" - Der Trick, zwischen einer Kette von Makroaufrufen zu wechseln gund hdiese fortzusetzen, funktioniert nicht unbedingt, da nicht festgelegt ist, ob die nächste gim Kontext der Erweiterung der ersten steht g. C11 fügt ein Beispiel zu 6.10.3.4 hinzu, um zu verdeutlichen, dass es nicht spezifiziert ist. (IIRC, der Präprozessor von TenDRA, lässt sich nicht beliebig erweitern.) Außerdem unterstützt keine Sprachversion sowohl leere Makroargumente als auch implizites int, sodass ein gültiges C-Programm nicht beide verwenden kann. :) Trotzdem schöne Antwort. Möchten Sie weiter Golf spielen?
HDV

@hvd: Ja, ich werde wahrscheinlich in ein paar Tagen darauf zurückkommen und nachsehen, ob ich Golf spielen kann. Sie haben definitiv Recht, dass dies ein nicht spezifiziertes Verhalten ist, aber ich denke, die Standardbehandlung hier ist, dass Sprachen durch ihre Implementierung definiert werden, so lange es mit gcc funktioniert, bin ich glücklich.
Julian Wolf

Ich habe nur den Kommentar angesprochen, den Sie in Ihrer Antwort angegeben haben, dass er sich nicht auf Spracherweiterungen stützt. Ja, auch mit Spracherweiterungen, es ist perfekt als Antwort hier gültig, wollte nicht anders vorschlagen.
HDV

Ah, das ist definitiv fair. Sie haben Recht, dass ich festlegen sollte, dass, obwohl keine zusätzlichen Flags erforderlich sind, dies möglicherweise nicht portabel ist.
Julian Wolf

Sie können mit *sanstelle von auf die leere Zeichenfolge testen strlen(s). C-Zeichenfolgen haben implizite Länge und werden mit einem charmit Wert abgeschlossen 0. Netter Makro-Hack, um einen Aufruf mit / ohne Argument zuzulassen!
Peter Cordes

4

8086 Maschinencode, 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

Dieser Maschinencode muss an der Adresse 0x100 sein und setzt das winzige Codemodell (cs = ds = es = ss) voraus. Der Funktionsort kann jedoch geändert werden, ohne dass zusätzliche Bytes anfallen. Wenn Sie den Wert auf Offset setzen 0, wird ein Byte ( xor si,sianstelle von mov si, 0x100) gespeichert.

Erforderliche Anrufkonvention

Dies setzt voraus, dass der Aufrufer mindestens 27 Bytes auf dem Stapel vorab zugewiesen hat. Es nimmt eine Zahl in axund gibt einen Funktionszeiger in zurück bx. Der Aufruf dieses Zeigers mit ax=0beendet die Kette und gibt die Summe in zurück bx.
Also für den ersten Anruf:

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

Dann für jeden nachfolgenden Anruf:

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

Zu beenden:

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

Ungolfed (kommentierte Demontage des Maschinencodes):

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

Nach dem Aufruf mit AX ungleich Null wird bx = spder Puffer mit einer geänderten Kopie des Maschinencodes von gefüllt function. Das 16-Bit-Direkt in der ersten Anweisung enthält die Summe. (Es ist von der letzten Anweisung vor dem geschrieben ret.)

push diIch pop bxkönnte durch mov bx, di(vorher rep movsb) ersetzt werden, was es einfacher macht, aber keine Einsparungen bringt.

Wenn der Aufrufer einen Zeiger an den dst-Puffer übergeben muss di, werden 4 Bytes gespart, verglichen mit der Berechnung in Bezug auf sp.

Wenn Sie die Startadresse der Funktion auf die gleiche Größe wie die Funktionsgröße einstellen, wird ein Byte ( mov cx, si) gespeichert .


Dies wäre eine bessere Antwort, wenn Sie die Zerlegung der Maschinencode-Bytes einschließen würden. Maschinencode-Antworten benötigen auf jeden Fall eine unbenutzte Version. zB verwenden objdump -b binarystatthexdump -C
Peter Cordes

Aktualisiert mit kommentierter Demontage. Mögliche Einsparungen: Der Aufrufer muss einen dst-Zeiger di(4 Byte) übergeben. Stellen Sie die Funktion Startadresse = Größe: mov cx, sistatt mov cx, 0x1b.
Peter Cordes

2

C #, 62 Bytes

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

Um den Anruf zu beenden, geben Sie eine negative Nummer ein, z

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

Ich möchte es zum Laufen bringen, indem ich nullkeine Parameter übergebe oder beende. Alle
meine

Können Sie !mstatt m<0und übergeben nulloder 0als letzten Parameter verwenden?
Betseg

@betseg Nein in C # nur Booleankann eingesetzt werden , werden Boolean... Ich habe versucht , mit nullaber es hat nur länger. Ich wollte benutzen, ??was bedeutet, wenn LHS null ist, mache RHS, aber da ich brauche, wenn LHS nicht null ist, mache ich dies, sonst mache ich RHS, ich konnte nicht.
TheLethalCoder

2

Scala, 58 Zeichen

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

Probieren Sie es online aus

Ungolfed:

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

Erläuterung:

Dieser Code definiert ein case classaufgerufenes f, wobei ein Konstruktor ein int übernimmt. Definieren Sie eine Case-Klasse, die die Methoden equals, hashcode, toString und copy generiert, und ein Begleitobjekt mit demselben Namen, um die Objekterstellung ohne das newSchlüsselwort zu ermöglichen .

Diese Klasse verfügt über eine überladene Apply-Methode: Eine verwendet eine andere Ganzzahl zum Hinzufügen und erstellt ein neues Objekt mit der aktualisierten Summe und eine ohne Argumente zum Abrufen der Summe.

In Scala kann jedes Objekt mit einer apply-Methode wie eine Methode aufgerufen werden, dh wie folgt o.apply(x)geschrieben werden o(x). Dies wird in der Standardbibliothek für Arrays, Listen, Maps und die Function1von anonymen Funktionen implementierten Merkmale verwendet


2

Pyth, 19 Bytes

DhdDebR?bh+dbdR$end

Probieren Sie es online!

Ich bin beeindruckt, dass Javascript Pyth schlägt, aber andererseits ist Pyth nicht so konzipiert, dass es Funktionen übergibt.


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

Was ist dazu erforderlich -M5.016? Es scheint, als ob Sie in der Lage sein sollten , ein paar Bytes zu löschen -M5.016und dann auch zu löschen myund zu speichern. Wenn es nur so ist say, können Sie -Estattdessen die Flagge verwenden, die nicht aktiviert wird use strict, sodass Sie die immer noch ablegen können my.
Chris

@Chris du hast recht, es braucht nicht 5.16, meine anfängliche Überarbeitung hat (mit __SUB__), aber ich habe das vor dem Absenden geändert und das Bit über 5.16 nicht entfernt. Ich werde das entfernen. Ich denke nicht, dass das Fallenlassen myrichtig wäre.
Hobbs

(und nein, ich zähle nicht sayals Teil des Codes, es ist nur zur Veranschaulichung)
Hobbs

1
Wenn Sie myohne entfernen use strict, $nist implizit eine globale Variable. Es ist eine schlechte Form in richtigen Perl-Skripten, aber in Einzeiler-Skripten ziemlich häufig, und es scheint hier zu funktionieren.
Chris

2

Brain-Flak , 6 Bytes

Eigentlich ist mir gerade aufgefallen, dass, da der ToS ein gültiges Rückgabeformat ist, das Poppen der 0 nicht wirklich benötigt wird, was 2 Bytes spart:

({{}})

Probieren Sie es online!

Ursprüngliche Einreichung (en), 8 Bytes

Verwendet 0als Sonderwert:

({{}}{})

Probieren Sie es online!

Erläuterung

Mit den Argumenten a 1 , a 2 ,…, a n , 0 sieht der Stack zunächst so aus:

                                                       a n

                                                       

                                                       a 2

                                                       a 1

                                                       0

Der Code geht dann auf, jede erscheint ein i , sammelt sie, springt der 0 fügt sie und legt das Ergebnis:

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

Alternative Lösungen, 8 Bytes

Anstatt die 0 zu platzieren und zur Summe hinzuzufügen, können wir auch die Stapel tauschen, da der rechte anfänglich leer ist:

({{}}<>)

Probieren Sie es online!

Mit dem -rFlag befindet sich die 0 oben auf dem Stapel, so dass wir sie zuerst platzieren können:

({}{{}})

Probieren Sie es online!

{}({{}})

Probieren Sie es online!


Oh meine Güte ... Großartig!
Eugene D. Gubenkov

2

C (GCC) 83 Bytes

Mein erstes C Golf! Es gibt ein paar andere C-Lösungen, aber diese sind etwas anders. Die Verwendung von Präprozessoren ist rein kosmetisch. Dieser Ansatz wurde zuerst in der Antwort von Conor O'Brien hier erörtert .

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

Der Endwert ist Null. Der Rückgabewert ist eine Vereinigung. Um das Ergebnis aufzurufen, verwenden Sie das Feld f, und um auf den Endwert zuzugreifen, verwenden Sie das Feld v, z

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

Probieren Sie es online

Einschränkungen

Eine globale Variable enthält die laufende Summe. Dies ist zwar ausdrücklich untersagt, die Übermittlung unterstützt jedoch wiederholte Aufrufe (die Gesamtsumme wird im Terminalaufruf zurückgesetzt), was der Grund für das Verbot des globalen Staates zu sein scheint.

Ein Zeiger auf fwird über das intMitglied in der zurückgegebenen Union gespeichert , sodass dies eindeutig nicht portierbar ist. Ich bin mir nicht sicher, ob dies auf GCC auf allen Plattformen oder nur auf Linux oder nur auf x86 oder nur mit ELF oder ... funktioniert.


2

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

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

0f

Probieren Sie es online!

Beendet durch Übergabe von Null. Aufrufsyntax:((0 f 1) 2) 0

-15 Bytes dank @ngn

Benötigt ⎕IO←0

Alle Golftipps sind willkommen!


Wenn Sie 0 als Terminator Wert verwenden können, ändern :If x<0zu :If×xund tauschen Sie die „if“ und „else“ Klauseln
ngn

Derp. Ich habe nicht gesehen, dass es "nicht positiv"
Zacharý

kennst du diesen trick r←⍎condition⊃'else' 'then'
25.


Dachte, dass sagte 22 ...> _ <
Zacharý


1

Dyvil , 34 Bytes

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

Verwendung :

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

Das Nachziehen ()kann weggelassen werden.

Erklärung :

Definiert einen Nebeneinanderstellungsoperator, der zwei Ints benötigt und diese hinzufügt. Der Parameter jhat den Standardwert 0, um den Aufruf ohne Argumente zu unterstützen. Das 0in den obigen Beispielen ist nicht der Name, sondern ein Literal.


1

Julia v0.5 +, 52 Bytes

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

Anrufen als F. Dies könnte wahrscheinlich durch die Anwendung einer weniger OO-Methode erheblich verkürzt werden, aber ich mag es immer, die Chance zu bekommen, diese Redewendung zu verwenden.

Wenn davon ausgegangen werden kann, dass "mindestens ein Anruf vor dem Beendigungsanruf getätigt wird", kann die zweite Zeile entfernt werden, um 6 Bytes zu sparen.



1

R, 40 Bytes

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

0 fungiert hier als Stoppwert. Für zwei weitere Bytes können wir es weglassen.

Das Problem ist, dass R ein knappes eingebautes Lambda fehlt. Aber wenn wir eins hinzufügen , können wir den Code auf 26 Bytes bringen :

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

(Ja, das ist gültig R. Es muss nur importiert werden.)


1

PHP, 44 Bytes

Eine Idee von @ user63956

Kündigungsruf 0

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

Online Version

Termination Anruf mit NULLbenötigen einen CAST [$i]zu[+$i]

PHP, 47 Bytes

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

Online Version

PHP, 52 Bytes

Abbruchaufruf NULLoder ein anderer Wert, der in PHP falsch ist

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

Wenn das Programm nach der Ausgabe beendet werden muss, ersetzen Sie es print$sdurch die("$s")+ 2 Bytes

Online Version


1
Ich denke, die Funktion sollte zurückkehren (nicht drucken) $s. so etwas könnte man return$i?f:$sam Ende machen
Conor O'Brien

@ ConorO'Brien Ich bin nicht sicher, aber wenn Ihr Denken richtig ist, könnte es 5 Bytes sparen Danke
Jörg Hülsermann

1
Ein paar Bytes können mit superglobalen Variablen gespeichert werden: function f($i){return[$_GET[0]+=$i][$i]?:f;}.
user63956

@ user63956 eine sehr schöne idee
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()}

Probieren Sie es online!

Testcode:

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

Ausgabe: 20


Sehr schön. Willkommen bei PPCG! Sie können ein Byte speichern, indem Sie $n="$args"anstelle von $n=$args[0]. Auf der anderen Seite wird es jedoch nicht funktionieren $args[0], da Sie dann eher eine Zeichenfolgenverkettung als eine Addition erhalten.
AdmBorkBork


1

Python, 69 Bytes

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

1
Ich nehme an, das ist Python? Sie sollten die in Ihrer Antwort verwendete Sprache angeben.
corvus_192

Können Sie versuchen, Ihre Antwort mehr Golf zu spielen? So wie es aussieht, ist es nicht sehr gut golfen.
20.

1

Oktave, 39 Bytes

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

* Argument des Beendigungsaufrufs ist 0.

Probieren Sie es online!

* endfunctionerforderlich, um weitere Codes hinzuzufügen.


1

R, 54 52 Bytes

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

2 Bytes gespart dank MickyT!

Ähnlich wie bei einer der Python-Antworten. Ungolfed:

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

Läuft als

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

1
Gute Arbeit. Sie können die internen Klammern um die if-Klausel entfernen. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT

Ich bin ein bisschen verwirrt, warum Ihre "ungolfed" Version hat return. returnin R ist nicht dasselbe wie in anderen Sprachen, es führt einen vorzeitigen Abbruch durch. Nichtbenutzung returnist idiomatisch. Auf der anderen Seite hat Ihre ungolfed Version immer noch den Golf if.
Konrad Rudolph

@KonradRudolph Der Golfer ifwar faul , aber der returndient nur der Lesbarkeit - er gibt das gleiche Ergebnis mit oder ohne return.
BLT

@BLT Hm. Ich bin der festen Überzeugung, dass R return die Lesbarkeit beeinträchtigt, weil es das Falsche signalisiert (vorzeitiges Verlassen) und ein Beispiel für die Programmierung von Frachtkult ist .
Konrad Rudolph

Cool, ich habe mal wieder was neues gelernt. Das ist ein Grund, warum ich immer wieder zurückkomme. Danke @KonradRudolph, auch diese Frage zum Stapelüberlauf
BLT

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.