Curry o dowolnej długości


53

Napisz funkcję, fktóra przyjmuje dodatnią liczbę całkowitą i zwraca funkcję.

Nowa zwrócona funkcja powinna być identyczna z f. Jednak gdy nastąpi „wywołanie zakończenia”, fzamiast tego należy zwrócić sumę wszystkich przekazanych liczb całkowitych.

Na przykład g=f(4)(jeśli fjest to pierwsza funkcja) należy ustawić gna inną funkcję. h=g(3)zrobi to samo. Jednak gdy wywołujesz hbez argumentów (szczegóły poniżej), powinien on wypisać 7, ponieważ jest to suma poprzednich argumentów funkcji. Innymi słowy, f(3)(4)() == 7.

Pamiętaj, że to nie to samo co f(3,4)().

„Połączenie kończące połączenie” to jedna z następujących opcji (do wyboru):

  • wywołanie bez argumentów
  • zerowy jako argument
  • wszelkie wartości dodatnie

Należy obsłużyć dowolną liczbę wywołań funkcji, nie ma z góry określonego limitu.

Gwarantujemy, że całkowita suma nie będzie większa niż 1 000.

Możemy założyć, że przed „połączeniem kończącym” wykonano co najmniej jedno połączenie.

Twój kod nie powinien używać statycznych zmiennych dla poszczególnych programów, więc powinno być możliwe przeprowadzenie eksperymentu wiele razy w tym samym środowisku wykonawczym i obserwowanie dokładnie tego samego zachowania.

Przykłady:

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

4
@LuisMendo Ogólnie oznacza, że f(4)zwraca nową funkcję. Jeśli ta nowa funkcja zostanie wywołana bez argumentów, zwróci 4, ale jeśli zostanie wywołana z innym argumentem, ponownie zwróci nową funkcję z tą samą semantyką, ale z dodanym nowym argumentem 4i tak dalej.
Martin Ender

6
@LuisMendo Rzeczywiście zależy to od Eugene'a, ale myślę, że zezwolenie na powtarzanie połączeń znacznie odbierze wyzwanie, ponieważ interesująca część nie polega na tworzeniu funkcji stanowej, ale na funkcji wyższego rzędu.
Martin Ender

6
@MartinEnder To ma sens. Eugene, jeśli taka jest intencja, proszę zmienić brzmienie wyzwania. Napisanie funkcji, którą można wywoływać w nieskończoność, wcale nie sugeruje, że funkcja powinna zwrócić funkcję
Luis Mendo

4
Czy możemy założyć, że naraz będzie tylko jedna instancja łańcucha połączeń? Np. Nie q = f(2)(3); b = f(1)(2)(3); q(); b()?
Conor O'Brien,

3
Niedawno wybrałem Haskell, jestem zainteresowany, czy jest to możliwe w Haskell. Silny system typów sprawia, że ​​myślę, że może nie być.
97 CAD

Odpowiedzi:


49

JavaScript (ES6), 18 bajtów

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

Przekaż wartość fałszowania, aby pobrać sumę. Zero można dopuścić za koszt 2 bajtów.

Wypróbuj online

Nie golfowany:

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

Genialne poddanie!
Eugene D. Gubenkov

21

Haskell (GHC), 118 bajtów

Jest to 98 bajtów dla kodu i 20 bajtów dla flagi kompilatora GHC -XFlexibleInstances, co umożliwia rozszerzenie systemu typów.

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

Definiuje to „funkcję” f, którą można wywołać z dowolną liczbą liczb całkowitych (), po której następuje jednostka , po czym zwraca liczbę całkowitą. Wpisz adnotacje są wymagane. Wypróbuj online!

Wyjaśnienie

Zmuszenie ścisłego systemu typów Haskell do umożliwienia tego wymaga pewnej magii, a mianowicie umożliwienia rozszerzenia GHC dla elastycznych instancji typu czcionki. Jak to działa, fjest to parametrycznie polimorficzna funkcja ograniczona przez ograniczenie klasy typu: jej typ to F a => Int -> a. Oznacza to, że fprzyjmuje liczbę całkowitą i zwraca wartość typu adla każdego typu anależącego do klasy F. Fjest tylko nazwą klasy, która udostępnia tę funkcję f; jest zadeklarowany w pierwszym wierszu.

Następne dwa wiersze to dwa wystąpienia Fróżnych typów a. Drugi wiersz mówi, że należy do typu funkcji od ()do liczb całkowitych F(gdzie ()jest typ jednostki, którego jedynym elementem jest wartość ()), a implementacja to f n () = n; funkcja zwraca swój pierwszy argument. Ostatni wiersz mówi, że jeśli anależy F, to także rodzaj funkcji od liczb całkowitych do a: z funkcji f :: Int -> amożemy wygenerować inną funkcję f :: Int -> Int -> a. Implementacja jest f m n = f (m+n)(kod używa kombinatorów, aby ją skrócić), gdzief po lewej stronie jest nowy, a fpo prawej stronie stary. To zasadniczo dajefnowy argument liczby całkowitej, który jest dodawany do następnego. Wiele argumentów jest sumowanych w następujący sposób:

  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

W fkażdej linii jest inny typ.

Funkcje Haskell są automatycznie curry, więc jeśli podasz ftylko liczby całkowite, otrzymasz funkcję.


1
Może irytuję, ale nie do końca tego wymaga wyzwanie. Definiujesz dwie (!) Funkcje, obie wywoływane f, a nie pojedynczą funkcję wykonującą zadanie. Jest to jednak tak blisko, jak to tylko możliwe w Haskell. Nie sądzę, że możliwe jest rozwiązanie zadania za pomocą jednej funkcji ze względu na ścisły system typów.
nimi

3
@nimi Definiuje nie dwie wywoływane funkcje f, ale nieskończenie wiele wywoływanych funkcji f. (Jeden na każdą możliwą liczbę argumentów.) Funkcje te (z tej nieskończonej rodziny) mają dwa rodzaje definicji, jeden rodzaj, gdy liczba argumentów wynosi zero, a drugi, gdy nie jest.
ShreevatsaR

@ShreevatsaR: Widzę dwie definicje, f n()=ni f=(f.).(+)tak bym nazwać definiowania dwie funkcje.
nimi 21.04.17

7
@nimi Istnieją dwie definicje, ale nie dwie funkcje. Liczba definicji nie musi być liczbą funkcji. Na przykład można zdefiniować funkcję silni z dwiema definicjami, g 0 = 1a g n = g (n-1) * ntam, gdzie są dwie definicje, ale tylko jedna funkcja. Mamy tutaj dwie definicje, ale nieskończenie wiele funkcji. (Każdy z innego rodzaju.)
ShreevatsaR

1
@nimi BTW in ghci załaduj powyższe i spróbuj :t f- powief :: F a => Int -> a (co oznacza, że ​​jeśli ajest instancją klasy f, to fjest funkcją Int -> a). Moglibyśmy więc uznać to za jedną funkcję lub za nieskończenie wiele, ale chociaż ma ona dwa rodzaje definicji (podobnie jak funkcja silnia), nie widzę żadnej dobrej podstawy do uznania jej za dwie funkcje.
ShreevatsaR

15

Python 2, 42 41 36 bajtów

To rozwiązanie nigdy nie będzie przepełnione, ponieważ Python obsługuje liczby całkowite o dowolnej dokładności. Zero to „wartość specjalna”.

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

Wypróbuj online

Nie golfowany:

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

14

C, 62 58 bajtów, konkurencja na granicy

Zaoszczędź 4 bajty dzięki Kevinowi! (Wciąż nie usuwa typedef, ponieważ jest to coś, co jest potrzebne do wywołania).

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

Funkcja do wywołania to f ; przestajesz to nazywać i otrzymujesz wynik, dzwoniąc na nie dodatni numer, taki jak 0. Wypróbuj uprząż testową online!

Tak więc, o ile mogę stwierdzić, jedynym sposobem na „curry” funkcje, które mają wiele typów zwrotów, jest wykonanie jednej z następujących czynności:

  1. Rzuć wynik na funkcję, aby poinformować kompilator, że chcesz ponownie wywołać wynik;
  2. lub utwórz union/struct typ który maint podtypy i funkcja / autoreferencyjne.

Próbowałem zrobić (2), ale wydawało mi się to trochę sprzeczne z duchem pytania i, szczerze mówiąc, prawie niemożliwe. Tak więc, zgodnie z duchem wyzwania, wybrałem opcję (1). Wymaga to rzutowania każdej zwróconej funkcji do funkcji, aby można było jej użyć.

Ta składnia „curry” wygląda nieco dziwnie, ale jest dość podobna. Aby naśladować f(21)(1), trzeba by pisać ((B)((B)f(21))(1))(0). Zdefiniowałem Btyp jako funkcję, która przyjmuje liczbę całkowitą i zwraca wskaźnik do funkcji, która przyjmuje liczbę całkowitą. Po rozwinięciu wygląda to następująco:

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

Jeśli powiesz, że kończy się tylko na 0, będziesz potrzebować rzutowania (co robisz w C, ponieważ C nie może poprawnie zdefiniować funkcji, która zwraca siebie), i pozostawiasz wyczyszczenie globalnego między biegami do wywołującego (który Myślę, że jest to całkowicie uzasadnione), możesz uprościć całą sprawę q;f(x){return x?(q+=x,f):q;}.
Kevin,


1
@ Kevin jeszcze, zgodnie z regułami witryny, funkcja musi być wielokrotnego użytku. Gdybym nie zerował qpo każdym uruchomieniu, funkcja nie byłaby już użyteczna
Conor O'Brien

Może wskaźniki funkcji? Trzeba będzie odwoływać się za każdym razem, ale warto sprawdzić
Downgoat

1
@ ConorO'Brien Właśnie realizowany swoje podejście Unii. Jest dłuższy niż ten, ale nie jest daleko.
Jakob

13

Mathematica, 25 bajtów

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

Wypróbuj online! (Korzystanie z matematyki.)

Można zrobić trzy bajty mniej, przenosząc odpowiedź JavaScript, ale chciałem przedstawić bardziej idiomatyczne rozwiązanie Mathematica. To @tylko odrobina cukru syntaktycznego, co sprawia, że ​​rozwiązanie jest równoważne z:

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

Więc tak, pomysł polega na tym, że w Mathematica nie można po prostu zdefiniować funkcji, f[x_]ale można bezpośrednio dołączyć wartość do bardziej skomplikowanego wyrażenia zawierającego fnp. f[x_]Przekazany inny argument. Ustawiając dwie definicje, możemy uzyskać pożądane zachowanie:

  • Pierwsza definicja łączy jedno f[x][y]wywołanie f[x+y], zużywając w ten sposób jedno „wywołanie” i sumując znajdujące się w nim argumenty. Ta zasada obowiązuje, dopóki nie zostaniemy f[sum][].
  • Druga definicja rozpakowuje ten ostatni przypadek, definiując całą rzecz do oceny sum.

1
<3 programowanie symboliczne
Julian Wolf

8

C ++, 72 bajty

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

Definiuje typ, Fktóry działa jako żądana funkcja, oraz zmienną ftego typu do wywołania. Jest ważny od C ++ 11 i działa z wersjami online GCC, clang, icc i VC ++.

Stosowanie:

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

Wyjaśnienie:

Po wstępnym przetworzeniu i ponownym sformatowaniu wygląda następująco:

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

Zwykle byłoby to napisane:

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

return a;i return {+a};zrób to samo, ponieważ unary +nie zmienia wartości, a nadmiarowe nawiasy klamrowe wokół wartości zwracanej są dozwolone. int mi int(m)zrobić to samo, ponieważ dozwolone są nadmiarowe nawiasy wokół nazwy zmiennej, w tym parametry funkcji. return {m+a};i return {int(m)+a};rób to samo, ponieważ rzut z mod intna intnie zmienia swojej wartości. Zmiany te operator()zbliżają dwa przeciążenia w składni, umożliwiając dwukrotne wywołanie definicji jednego makra. Wybór odpowiedniej kolejności dla trzech elementów umożliwia uwzględnienie również pierwszego słowa następnego wiersza ( int) w definicji makra.


1
Piękny. I nie tylko rozwiązanie w golfa ... przeciążenie, operator()aby ta praca była szczególnie fajna.
Ray Toal,

6

Rubinowy, 23 bajty

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

Stosowanie:

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

6

C, 104 96 bajtów

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

Używa metody z linku udostępnionego przez @JulianWolf. Ostatni argument musi wynosić 0.

Wypróbuj online!


Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Dennis,

4

Math.JS, 38 bajtów

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

Zadzwoń za pomocą f(number_a)(number_b)(...)(negative_number)

Jeśli wolno nam określić początkowe wywołanie, f(x)=i(x,0)\nmożna usunąć 12 bajtów ( ) i można je wywołać za pomocąi(number_one,0)(number_two)(...)(negative_number)

Spróbuj!

Wyjaśnienie

LaTeX!

Jak pokazano w powyższym LaTex, f(x)po prostu wywołuje i(x,0), a następnie i(x,y)zwraca wartość yif xjest mniejsza niż 0 lub funkcję j(z)=i(z,x+y), która pobiera jeden argument, który zapętla się. Zwiększenie wartości y.


4

C, 232 206 bajtów

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

Prawdopodobnie można to znacznie pograć w golfa, ale powinno to służyć jako dowód na to, że można używać C bez żadnych rozszerzeń języka *, aby rozwiązać ten problem, wywołując bez argumentów, a nie z magiczną wartością.

* @hvd zauważył, że chociaż działa to od razu przy użyciu gcc, niektóre zachowania nie są zdefiniowane w standardzie C, co oznacza, że ​​może nie być przenośne. Używaj na własne ryzyko!

Nie golfowany:

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

Kompilowanie i uruchamianie z gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingwyjściami (po ostrzeżeniach)

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

„bez żadnych rozszerzeń językowych” - Nie można zagwarantować, że na przemian gi hkontynuacji łańcucha wywołań makr będzie działać, ponieważ nie jest określone, czy następne gpojawi się w kontekście rozszerzenia pierwszego g. C11 dodaje przykład do 6.10.3.4, aby przeliterować, że nie jest określony. (IIRC, preprocesor TenDRA to taki, który nie rozwinąłby go tak, jak chcesz.) Poza tym żadna wersja języka nie obsługuje zarówno pustych argumentów makr, jak i domyślnej int, więc prawidłowy program C nie może używać obu. :) Mimo to fajna odpowiedź. Czy chcesz dalej grać w golfa?
hvd

@hvd: tak, pewnie wrócę do tego za kilka dni i zobaczę, czy mogę zagrać w golfa. Zdecydowanie masz rację, że jest to nieokreślone zachowanie, ale myślę, że standardowym podejściem tutaj jest to, że języki są definiowane przez ich implementację, więc dopóki działa z gcc, jestem szczęśliwy.
Julian Wolf

Właśnie odpowiadałem na komentarz, który podałeś w swojej odpowiedzi, że nie opiera się on na żadnych rozszerzeniach języka. Tak, nawet w przypadku rozszerzeń językowych, jest tu całkowicie poprawna odpowiedź, nie chciałem sugerować inaczej.
hvd

Ach, to zdecydowanie sprawiedliwe. Masz rację, że powinienem zastrzec, że chociaż nie są wymagane dodatkowe flagi, może nie być przenośne.
Julian Wolf

Możesz przetestować pusty ciąg za pomocą *szamiast strlen(s). Ciągi C mają długość niejawną, zakończoną charwartością 0. Fajny hack makr, który pozwala na rozmowy z / bez arg!
Peter Cordes

4

Kod maszynowy 8086, 27 bajtów

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

Ten kod maszynowy musi mieć adres 0x100 i zakłada model małego kodu (cs = ds = es = ss). Lokalizacja funkcji może być jednak zmieniona bez dodatkowych kosztów. Ustawienie go w pozycji offset 0spowoduje zapisanie bajtu ( xor si,sizamiast mov si, 0x100)

Wymagana konwencja połączeń

Zakłada się, że dzwoniący wstępnie przydzielił co najmniej 27 bajtów na stosie. Pobiera liczbę axi zwraca wskaźnik funkcji bx. Wywołanie tego wskaźnika z ax=0kończy łańcuch i zwraca sumę bx.
Więc dla pierwszego połączenia:

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

Następnie dla każdego kolejnego połączenia:

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

Aby zakończyć:

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

Unngolfed (skomentował demontaż kodu maszynowego):

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

Po wywołaniu tego niezerowym AX, bx = spa bufor jest wypełniony zmodyfikowaną kopią kodu maszynowego z function. 16-bitowy natychmiast w pierwszej instrukcji zawiera sumę. (Jest napisany przez ostatnią instrukcję przed ret.)

push di/ pop bxmożna zastąpić mov bx, di(przed rep movsb), dzięki czemu jest to prostsze, ale nie ma oszczędności.

Wymaganie od dzwoniącego przekazania wskaźnika do bufora dst w dizaoszczędziłoby 4 bajty w porównaniu do obliczenia go względemsp .

Ustawienie adresu początkowego funkcji na taki sam jak rozmiar funkcji pozwoliłoby zaoszczędzić bajt ( mov cx, si).


To byłaby lepsza odpowiedź, jeśli uwzględnisz demontaż bajtów kodu maszynowego. odpowiedzi na kod maszynowy zdecydowanie potrzebują wersji bez golfa. np. użyj objdump -b binaryzamiasthexdump -C
Peter Cordes

Zaktualizowano z komentowanym demontażem. Możliwe oszczędności: wymagaj od dzwoniącego przekazania wskaźnika dst di(4 bajty). Ustaw adres początkowy funkcji = rozmiar: mov cx, sizamiast mov cx, 0x1b.
Peter Cordes,

2

C #, 62 bajty

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

Aby zakończyć połączenie, podaj liczbę ujemną, np

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

Chciałbym, aby działał, przekazując nullparametry lub nie kończąc żadnych parametrów. Jednak wszystkie sposoby próbowałem były o wiele dłużej
TheLethalCoder

Czy możesz użyć !mzamiast m<0i przekazać nulllub 0jako ostatni parametr?
betseg 20.04.17

@betseg Nie w C # tylko a Booleanmoże być użyte jako Boolean... Próbowałem z, nullale właśnie się wydłużyło. Chciałem użyć, ??co oznacza, że ​​jeśli LHS ma wartość zerową, to RHS, ale ponieważ potrzebuję, jeśli LHS nie jest zerowe, zrób to inaczej RHS, czego nie mogłem.
TheLethalCoder

2

Scala, 58 znaków

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

Wypróbuj online

Nie golfowany:

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

Wyjaśnienie:

Ten kod definiuje case classnazwany f z konstruktorem przyjmującym wartość int. Zdefiniuj klasę przypadków, która wygeneruje metody equals, hashcode, toString i copy oraz obiekt towarzyszący o tej samej nazwie, aby umożliwić tworzenie obiektów bez newsłowa kluczowego.

Ta klasa ma przeciążoną metodę zastosuj: jedna bierze kolejną liczbę całkowitą, aby dodać i tworzy nowy obiekt ze zaktualizowaną sumą, a druga bez argumentów, aby uzyskać sumę.

W Scali każdy obiekt z metodą zastosuj można nazwać jak metodę, czyli o.apply(x)można ją zapisać jako o(x). Jest to używane w standardowej bibliotece dla tablic, list, map i Function1cechy implementowanej przez funkcje anonimowe


2

Pyth, 19 bajtów

DhdDebR?bh+dbdR$end

Wypróbuj online!

Jestem pod wrażeniem, że JavaScript pokonuje Pytha, ale z drugiej strony Pyth nie jest zaprojektowany do przekazywania funkcji.


2

Perl 5, 36 bajtów

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

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

Co z tym wymaga -M5.016? Wygląda na to, że powinieneś być w stanie upuścić, -M5.016a następnie upuścić myi zapisać kilka bajtów. Jeśli tak say, możesz -Ezamiast tego użyć flagi , która się nie aktywuje use strict, więc nadal możesz upuścić my.
Chris

@Chris masz rację, nie potrzebuje 5.16, moja początkowa wersja zrobiła (używałem __SUB__), ale zmieniłem to przed przesłaniem i nie usunąłem trochę o 5.16. Usunę to. Nie sądzę jednak, aby upuszczanie mybyło poprawne.
hobbs

(i nie, nie liczę sayjako część kodu, to tylko w celach ilustracyjnych)
hobbs

1
Jeśli usuniesz mybez use strict, $njest to domyślnie zmienna globalna. Jest to zła forma w odpowiednich skryptach perla, ale jest dość powszechna w liniowcach i wydaje się, że tutaj działa.
Chris

2

Brain-Flak , 6 bajtów

Właśnie zauważyłem, że skoro ToS jest poprawnym formatem zwrotnym, wyskakiwanie 0 nie jest tak naprawdę potrzebne, co pozwala zaoszczędzić 2 bajty:

({{}})

Wypróbuj online!

Oryginalne zgłoszenia, 8 bajtów

Wykorzystuje 0jako specjalną wartość:

({{}}{})

Wypróbuj online!

Wyjaśnienie

Biorąc pod uwagę argumenty u 1 , 2 , ..., n , 0 stos początkowo wygląda następująco:

                                                       a n

                                                       

                                                       a 2

                                                       a 1

                                                       0

Następnie kod jest długa, co pojawia się I , gromadzi je zdejmuje 0 dodaje je i odkłada wynik:

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

Alternatywne rozwiązania, 8 bajtów

Zamiast wstawiać 0 i dodawać je do sumy, możemy również zamieniać stosy, ponieważ prawy jest początkowo pusty:

({{}}<>)

Wypróbuj online!

Używając -rflagi, 0 znajduje się na górze stosu, więc możemy ją najpierw wstawić:

({}{{}})

Wypróbuj online!

{}({{}})

Wypróbuj online!


O mój Boże ... Świetny!
Eugene D. Gubenkov

2

C (GCC), 83 bajty

Mój pierwszy golf C! Istnieje kilka innych rozwiązań C, ale to jest trochę inne. Zastosowanie preprocesora jest czysto kosmetyczne. To podejście zostało po raz pierwszy omówione w odpowiedzi Conora O'Briena tutaj .

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

Wartość końcowa wynosi zero. Zwracana wartość to unia, więc aby wywołać wynik, użyć pola fi uzyskać dostęp do wartości końcowej, użyj pola v, np

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

Wypróbuj online

Ograniczenia

Zmienna globalna zawiera bieżącą sumę. Chociaż jest to wyraźnie zabronione, przesyłanie obsługuje wielokrotne wywołania (suma jest resetowana w wywołaniu terminalu), co wydaje się być przyczyną zakazu stanu globalnego.

Wskaźnik do fjest przechowywany w zwrócony związek za pośrednictwem intelementu, więc najwyraźniej nie jest przenośny. Nie jestem pewien, czy to działa w GCC na wszystkich platformach, czy tylko na Linuksie, czy tylko na x86, czy tylko z ELF lub ... Jeśli ktoś zna jakieś szczegóły na ten temat, proszę o komentarz lub wiadomość!


2

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

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

0f

Wypróbuj online!

Kończy się, przekazując zero. Składnia wywołania:((0 f 1) 2) 0

-15 bajtów dzięki @ngn

Wymaga ⎕IO←0

Wszelkie wskazówki dotyczące gry w golfa są mile widziane!


jeśli można użyć jako wartość 0 terminatora, należy zmienić :If x<0, aby :If×xi zamienić „jeśli” i „else” klauzule
NGN

Derp. Nie widziałem, żeby było napisane „nie-pozytywne”
Zacharý

znasz tę sztuczkę? r←⍎condition⊃'else' 'then'
ngn


Myślałem, że powiedział 22 ...> _ <
Zacharý


1

Dyvil , 34 bajty

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

Zastosowanie :

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

Końcowe () można pominąć.

Wyjaśnienie :

Definiuje operator zestawienia, który pobiera dwie liczby int i dodaje je. Ten parametr jma wartość domyślną 0do obsługi połączenia bez argumentów. W 0powyższych przykładach nie jest to nazwa, ale dosłownie.


1

Julia v0.5 +, 52 bajty

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

Zadzwoń jako F . Prawdopodobnie można by to znacznie skrócić, przyjmując mniej OO, ale zawsze lubię mieć możliwość korzystania z tego idiomu.

Jeśli można założyć, że „co najmniej jedno połączenie zostanie wykonane przed połączeniem kończącym”, drugą linię można usunąć, aby zaoszczędzić 6 bajtów.



1

R, 40 bajtów

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

0 działa tutaj jako wartość stop. W przypadku dwóch kolejnych bajtów możemy to pominąć.

Problem polega na tym, że R nie ma zwięzłej wbudowanej lambda. Ale jeśli dodamy jeden , możemy uzyskać kod do 26 bajtów :

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

(Tak, to jest poprawne R. Wystarczy importować.)


1

PHP, 44 bajty

Pomysł od @ user63956

Zakończenie połączenia 0

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

Wersja online

Zakończenie połączenia z NULLpotrzebują oddanych [$i]do[+$i]

PHP, 47 bajtów

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

Wersja online

PHP, 52 bajty

Wywołanie zakończenia NULLlub dowolna inna wartość fałszywa w PHP

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

jeśli program musi zakończyć po wyjściu zastąpić print$sz die("$s")+ 2 bajty

Wersja online


1
Myślę, że funkcja powinna wrócić (nie drukować) $s. żebyś mógł zrobić coś takiego jak return$i?f:$sna końcu
Conor O'Brien

@ ConorO'Brien Nie jestem pewien, ale jeśli twoje myślenie jest słuszne, może zaoszczędzić 5 bajtów. Dziękuję
Jörg Hülsermann

1
Kilka bajtów mogą być zapisywane ze zmiennymi superglobalnych: function f($i){return[$_GET[0]+=$i][$i]?:f;}.
user63956,

@ user63956 bardzo fajny pomysł
Jörg Hülsermann 20.04.17

1

PowerShell, 86 bajtów

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

Wypróbuj online!

Kod testowy:

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

Wyjście: 20


Bardzo dobrze. Witamy w PPCG! Możesz zapisać bajt, wykonując $n="$args"zamiast $n=$args[0]. To jednak nie będzie działać na drugim $args[0], ponieważ wtedy uzyskasz konkatenację łańcuchów zamiast dodawania.
AdmBorkBork


1

Python, 69 bajtów

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

1
Zakładam, że to python? W odpowiedzi należy podać język.
corvus_192

Czy możesz spróbować jeszcze bardziej pograć w golfa? W obecnej formie nie jest zbyt dobrze golfowy.
Rɪᴋᴇʀ 20.04.17

1

Oktawa, 39 bajtów

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

* Argumentem zakończenia połączenia jest 0.

Wypróbuj online!

* endfunctionwymagane, aby dodać kilka innych kodów.


1

R, 54 52 bajtów

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

Zaoszczędź 2 bajty dzięki MickyT!

Podobne do jednej z odpowiedzi na python. Nie golfowany:

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

Działa jako

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

1
Dobra robota. Możesz pozbyć się wewnętrznych nawiasów klamrowych wokół klauzuli if. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT,

Jestem trochę zdziwiony, dlaczego twoja wersja „bez golfa” ma return. returnw R nie jest taki sam jak w innych językach, wykonuje przedwczesne przerwanie. Nieużywanie returnjest idiomatyczne. Z drugiej strony twoja nie golfowa wersja wciąż ma golfa if.
Konrad Rudolph,

@KonradRudolph Grał w golfa iflenistwo, ale returnjest tylko dla czytelności - daje ten sam wynik z lub bez return.
BLT,

@BLT Hm. Uważam, że nieuzasadnione w R return zmniejsza czytelność, ponieważ sygnalizuje niewłaściwą rzecz (przedwczesne wyjście) i jest przykładem programowania kultowego ładunku .
Konrad Rudolph,

Fajnie, znowu nauczyłem się czegoś nowego. To jeden z powodów, dla których wciąż wracam. Dzięki @KonradRudolph, również to pytanie dotyczące przepełnienia stosu jest interesujące: stackoverflow.com/questions/11738823/...
BLT

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.