Curry-longueur arbitraire


53

Ecrivez une fonction fqui prend un entier positif et retourne une fonction.

La nouvelle fonction renvoyée doit être identique à f. Cependant, lorsque "l'appel de terminaison" se produit, fdoit plutôt renvoyer la somme de tous les entiers passés.

Par exemple, g=f(4)(si fest la première fonction) doit être défini gsur une autre fonction. h=g(3)va faire la même chose. Cependant, lorsque vous appelez hsans argument (voir ci-dessous pour plus de détails), il doit générer 7, car c'est la somme des arguments de la fonction précédente. Autrement dit, f(3)(4)() == 7.

Notez que ce n'est pas la même chose que f(3,4)().

"Appel de terminaison" est l’une des options suivantes (à vous de choisir):

  • appel sans arguments
  • null comme argument
  • toute valeur non positive

Une quantité arbitraire d'appels de fonction doit être prise en charge, il n'y a pas de limite prédéfinie.

Il est garanti que la somme totale ne sera pas supérieure à 1'000.

Nous pouvons supposer qu'il y a au moins un appel passé avant "l'appel de terminaison".

Votre code ne doit pas utiliser de variables statiques, par programme. Il doit donc être possible d'exécuter le test plusieurs fois au cours de la même exécution et d'observer exactement le même comportement.

Exemples:

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

4
@LuisMendo Cela signifie généralement que f(4)renvoie une nouvelle fonction. Si cette nouvelle fonction est appelée sans arguments, elle retourne 4, mais si elle est appelée avec un autre argument, elle retournera à nouveau une nouvelle fonction avec la même sémantique mais avec le nouvel argument ajouté à 4and etc..
Martin Ender

6
@LuisMendo C'est en effet à Eugene, mais je pense que permettre des appels répétés réduirait considérablement le défi, car la partie intéressante ne consiste pas à créer une fonction avec état mais à une fonction supérieure.
Martin Ender

6
@MartinEnder Cela fait beaucoup de sens. Eugene, si c'est l'intention, veuillez changer le libellé du défi. Écrire une fonction qui peut être appelée à l'infini n'indique nullement que la fonction devrait renvoyer une fonction
Luis Mendo

4
Pouvons-nous supposer qu'il n'y aura qu'une instance de la chaîne d'appels à la fois? Par exemple, non q = f(2)(3); b = f(1)(2)(3); q(); b()?
Conor O'Brien

3
Comme je viens juste de prendre Haskell, je voudrais savoir si cela est possible à Haskell. Le système de type fort me fait penser que ce n’est peut-être pas le cas.
CAD97

Réponses:


49

JavaScript (ES6), 18 octets

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

Passez une valeur de fausseté pour récupérer la somme. Les zéros pourraient être autorisés pour un coût de 2 octets.

Essayez-le en ligne

Ungolfed:

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

Soumission brillante!
Eugene D. Gubenkov

21

Haskell (GHC), 118 octets

Il s'agit de 98 octets pour le code et de 20 octets pour l'indicateur de compilation GHC -XFlexibleInstances, qui active une extension de système de types.

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

Ceci définit une "fonction" f, qui peut être appelée avec un nombre arbitraire d'entiers suivi de l'unité (), après quoi elle retourne un entier. Les annotations de type sont obligatoires. Essayez-le en ligne!

Explication

Forcer le système de types strict de Haskell à permettre cela nécessite une certaine magie, à savoir l'activation de l'extension GHC pour des instances de classes de types flexibles. Cela fonctionne comme fune fonction polymorphe paramétrée restreinte par une contrainte de classe de type: son type est F a => Int -> a. Cela signifie que fprend un entier et retourne une valeur de type a, pour tout type aappartenant à la classe de types F. Fest simplement le nom de la classe de types qui fournit la fonction f; c'est déclaré sur la première ligne.

Les deux lignes suivantes sont deux instances de Ftypes différents a. La deuxième ligne indique ()à Fquel type de fonctions de en entiers appartient (où ()est le type d'unité dont le seul membre est la valeur ()), et l'implémentation est f n () = n; la fonction retourne son premier argument. La dernière ligne indique que si aappartient à F, alors le type de fonctions allant d’entiers à a: à partir d’une fonction, f :: Int -> anous pouvons générer une autre fonction f :: Int -> Int -> a. L'implémentation est la suivante f m n = f (m+n)(le code utilise des combinateurs pour le rendre plus court), où le plus fà gauche est le nouveau et le plus fà droite est l'ancien. Cela donne essentiellementfun nouvel argument entier, qui est ajouté au suivant. Plusieurs arguments sont résumés comme suit:

  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

Le fsur chaque ligne a un type différent.

Les fonctions Haskell sont automatiquement configurées, donc si vous fne donnez que des entiers, vous obtenez une fonction.


1
Peut-être suis-je nerveux, mais ce n'est pas tout à fait ce que le défi demande. Vous définissez deux (!) Fonctions, les deux appelées f, pas une seule fonction qui fait le travail. Cependant, c'est aussi proche que possible de Haskell. Je ne pense pas qu'il soit possible de résoudre la tâche avec une seule fonction à cause du système de types strict.
nimi

3
@nimi Ceci ne définit pas deux fonctions appelées f, mais un nombre infini de fonctions appelées f. (Un pour chaque nombre possible d'arguments.) Ces fonctions (de cette famille infinie) ont deux sortes de définitions: une sorte lorsque le nombre d'arguments est égal à zéro et une autre quand ce n'est pas le cas.
ShreevatsaR

@ShreevatsaR: Je vois deux définitions f n()=net f=(f.).(+)je l'appellerais donc définir deux fonctions.
nimi

7
@nimi Il existe deux définitions, mais pas deux fonctions. Le nombre de définitions ne doit pas nécessairement être le nombre de fonctions. Par exemple, vous pouvez définir la fonction factorielle avec les deux définitions g 0 = 1et g n = g (n-1) * n, où il y a deux définitions mais une seule fonction. Nous avons ici deux définitions mais une infinité de fonctions. (Chacun d'un type différent.)
ShreevatsaR

1
@nimi BTW ghcicharge ce qui précède et essaie :t f- il dira f :: F a => Int -> a(ce qui signifie que si aest une instance de classe f, alors fest une fonction Int -> a). Nous pourrions donc considérer cela comme une fonction ou une infinité d’activités, mais bien qu’il ait deux sortes de définitions (tout comme la fonction factorielle), je ne vois aucune base valable pour considérer qu’il s’agit de deux fonctions.
ShreevatsaR

15

Python 2, 42 41 36 octets

Cette solution n'aura jamais de débordement, car Python prend en charge les entiers à précision arbitraire. Zéro est la "valeur spéciale".

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

Essayez-le en ligne

Ungolfed:

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

14

C, 62 58 octets, limite en concurrence

4 octets sauvés grâce à Kevin! (Vous ne supprimez toujours pas typedef car c'est un élément nécessaire pour pouvoir être appelé.)

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

La fonction à appeler est f; vous arrêtez de l'appeler et obtenez le résultat en l'appelant avec un nombre non positif comme 0. Essayez un test de harnais en ligne!

Donc, autant que je sache, le seul moyen de "curry" des fonctions ayant plusieurs types de retour consiste à effectuer l'une des opérations suivantes:

  1. Transformez le résultat en fonction pour indiquer au compilateur que vous souhaitez rappeler le résultat.
  2. ou créez un union/ structtype qui a un sous-type intet une fonction / auto-référentielle.

J'ai essayé de le faire (2), mais cela semblait un peu contraire à l'esprit de la question et, franchement, presque impossible. Ainsi, dans l’esprit du challenge, j’ai opté pour l’option (1). Cela nécessite de transformer chaque fonction retournée en une fonction, afin qu'elle puisse être utilisée.

Cette syntaxe "currying" semble un peu étrange, mais est assez similaire. Pour imiter f(21)(1), il faudrait écrire ((B)((B)f(21))(1))(0). J'ai défini le Btype comme étant une fonction qui prend un entier et renvoie un pointeur sur une fonction qui prend un entier. Développé, cela ressemble à:

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

Si vous dites qu'il se termine uniquement sur 0, vous aurez besoin de la conversion (ce que vous faites en C, car celui-ci ne peut pas définir correctement une fonction qui se retourne elle-même), et vous laissez l'effacement de la globale entre les exécutions à l'appelant (qui Je pense est parfaitement raisonnable), vous pouvez simplifier le tout q;f(x){return x?(q+=x,f):q;}.
Kevin


1
@ Kevin encore, conformément aux règles du site, une fonction doit être réutilisable. Si je ne faisais pas zéro qaprès chaque manche, alors la fonction ne serait plus utilisable
Conor O'Brien

Peut-être que des pointeurs de fonction? Vous auriez à faire référence à chaque fois, mais il pourrait être intéressant de vérifier
Downgoat

1
@ ConorO'Brien Je viens de mettre en œuvre votre approche syndicale. C'est plus long que celui-ci, mais ce n'est pas loin.
Jakob

13

Mathematica, 25 octets

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

Essayez-le en ligne! (Utilisation des mathématiques.)

Il est possible de faire trois octets de moins en portant la réponse JavaScript, mais je voulais présenter une solution Mathematica plus idiomatique. C'est @juste un peu de sucre syntaxique, ce qui rend la solution équivalente à:

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

Donc, l'idée est que dans Mathematica, vous ne pouvez pas simplement définir une fonction, f[x_]mais vous pouvez également associer directement une valeur à une expression plus complexe f, par exemple f[x_]en passant un autre argument. En définissant deux définitions pour cela, nous pouvons obtenir le comportement souhaité:

  • La première définition réduit un f[x][y]appel en f[x+y], consommant ainsi un "appel" et ajoutant les arguments à l'intérieur. Cette règle s'applique jusqu'à ce qu'il ne nous reste plus f[sum][].
  • La deuxième définition décompresse ce dernier cas en définissant le tout à évaluer sum.

1
<3 programmation symbolique
Julian Wolf

8

C ++, 72 octets

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

Ceci définit un type Fqui agit comme la fonction demandée et une variable fde ce type à appeler. Il est valable à partir de C ++ 11 et fonctionne avec les versions en ligne de GCC, clang, icc et VC ++.

Usage:

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

Explication:

Après prétraitement et reformatage, il se présente comme suit:

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

Ceci s’écrirait normalement:

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

return a;et return {+a};faites la même chose, car unary +ne change pas la valeur, et les accolades redondantes autour de la valeur de retour sont autorisées. int met int(m)faire la même chose, car les parenthèses redondantes autour d'un nom de variable sont autorisées, y compris les paramètres de fonction. return {m+a};et return {int(m)+a};faire la même chose, comme un casting de mpartir intpour intne change pas sa valeur. Ces modifications operator()rapprochent la syntaxe des deux surcharges, permettant ainsi d'invoquer deux fois une même définition de macro. Choisir le bon ordre pour les trois membres permet intégalement d'inclure le premier mot de la ligne suivante ( ) dans la définition de macro.


1
Magnifique. Et pas seulement la solution au golf… la surcharge operator()pour faire ce travail était particulièrement cool.
Ray Toal

6

Ruby, 23 octets

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

Usage:

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

6

C, 104 à 96 octets

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

Utilise la méthode du lien partagé par @JulianWolf. Le dernier argument doit être 0.

Essayez-le en ligne!


Les commentaires ne sont pas pour une discussion prolongée; cette conversation a été déplacée pour discuter .
Dennis

4

Math.JS, 38 octets

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

Appelez-le avec f(number_a)(number_b)(...)(negative_number)

Si nous sommes autorisés à spécifier l'appel initial, vous f(x)=i(x,0)\npouvez supprimer 12 octets ( ) et l'appelez aveci(number_one,0)(number_two)(...)(negative_number)

Essayez le!

Explication

Latex!

Comme indiqué ci-dessus, LaTex f(x)appelle simplement i(x,0), puis i(x,y)renvoie la valeur yif si xest inférieure à 0, ou la fonction j(z)=i(z,x+y)qui prend un argument, qui est bouclé. Ajout à la valeur de y.


4

C, 232 206 octets

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

Cela peut probablement être joué de manière significative, mais devrait servir de preuve du concept que C peut être utilisé, sans aucune extension de langage *, pour résoudre ce problème en appelant sans arguments plutôt qu'avec une valeur magique.

* @hvd a noté que, bien que cela fonctionne immédiatement avec gcc, une partie du comportement n'est pas définie dans la norme C, ce qui signifie que cela peut ne pas être portable. À utiliser à vos risques et périls!

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

Compiler et exécuter avec des gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingsorties (après quelques avertissements)

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

"sans extension de langue" - Il n’est pas certain que l’ astuce consistant à alterner get hà continuer une chaîne d’invocations de macros fonctionne, car il n’est pas précisé si la prochaine gapparaît dans le contexte de l’extension de la première g. C11 ajoute un exemple à 6.10.3.4 pour préciser qu'il n'est pas spécifié. (IIRC, le préprocesseur de TenDRA en est un qui ne pourrait pas être étendu comme vous le souhaitez.) Hormis cela, aucune version du langage ne prend en charge les arguments de macro vides et les int implicites. Par conséquent, un programme C valide ne peut pas utiliser les deux. :) Toujours, bonne réponse. Cherchez-vous à jouer au golf plus loin?
hvd

@hvd: Oui, j'y reviendrai probablement dans quelques jours pour voir si je peux jouer au golf. Vous avez certainement raison de dire qu'il s'agit d'un comportement non spécifié, mais je pense que le traitement standard ici est que les langues sont définies par leur implémentation. Par conséquent, tant que cela fonctionne avec gcc, je suis heureux.
Julian Wolf

Je viens de répondre au commentaire que vous avez inclus dans votre réponse selon lequel cela ne repose sur aucune extension de langue. Oui, même avec les extensions de langue, c’est une réponse parfaitement valable, cela ne veut pas dire le contraire.
hvd

Ah, c'est vraiment juste. Vous avez raison, je devrais préciser que, même si aucun drapeau supplémentaire n'est requis, cela peut ne pas être portable.
Julian Wolf

Vous pouvez tester la chaîne vide avec *sau lieu de strlen(s). Les chaînes C ont une longueur implicite et se terminent par une charvaleur with 0. Nice hack macro pour permettre un appel avec / sans argument!
Peter Cordes

4

8086 code machine, 27 octets

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

Ce code machine doit être à l'adresse 0x100 et suppose le modèle de code minuscule (cs = ds = es = ss). L'emplacement de la fonction peut cependant être modifié sans que cela ne coûte des octets supplémentaires. Le mettre en décalage 0permettrait d'économiser un octet ( xor si,siau lieu de mov si, 0x100)

Convention d'appel obligatoire

Cela suppose que l'appelant a pré-alloué au moins 27 octets sur la pile. Il prend un nombre axet renvoie un pointeur de fonction bx. L'appel de ce pointeur avec ax=0termine la chaîne et renvoie la somme en bx.
Donc pour le premier appel:

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

Ensuite, pour chaque appel suivant:

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

Terminer:

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

Ungolfed (désassemblage commenté du code machine):

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

Après avoir appelé cela avec AX non nul, bx = sple tampon est rempli avec une copie modifiée du code machine de function. L'instantané 16 bits de la première instruction contient le total. (Il est écrit par la dernière instruction avant le ret.)

push di/ pop bxpourrait être remplacé par mov bx, di(avant rep movsb), le rendant plus simple mais pas d'économies.

Demander à l'appelant de passer un pointeur sur la mémoire tampon dst dipermettrait de gagner 4 octets au lieu de le calculer par rapport à sp.

Si l'adresse de début de la fonction est identique à la taille de la fonction, vous économiserez un octet ( mov cx, si).


Ce serait une meilleure réponse si vous incluiez le désassemblage des octets de code machine. Les réponses en code machine ont définitivement besoin d'une version non golfée. p.ex. utiliser objdump -b binaryau lieu dehexdump -C
Peter Cordes

Mis à jour avec le désassemblage commenté. Économies possibles: demander à l'appelant de passer un pointeur dst di(4 octets). Rendre la fonction adresse de départ = taille: mov cx, siau lieu de mov cx, 0x1b.
Peter Cordes

2

C #, 62 octets

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

Pour mettre fin à l’appel, passez un numéro négatif, par exemple

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

Je voudrais le faire fonctionner en passant nullou aucun paramètre à la fin. Cependant, tous les moyens que j'ai essayés étaient beaucoup plus longs
TheLethalCoder

Pouvez-vous utiliser à la !mplace de m<0et passer nullou 0comme dernier paramètre?
mardi

@betseg Non, en C #, seul un Booleanpeut être utilisé en tant que Boolean... J'ai essayé avec nullmais cela a juste pris plus de temps. Je voulais utiliser ??ce qui signifie que si LHS est nul, faire RHS, mais comme j'ai besoin de si LHS n'est pas nul, faire ceci sinon faire RHS, je ne pourrais pas.
TheLethalCoder

2

Scala, 58 caractères

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

Essayez-le en ligne

Ungolfed:

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

Explication:

Ce code définit un case classf appelé avec un constructeur prenant un int. Définissez une classe de cas qui générera les méthodes equals, hashcode, toString et copy, ainsi qu'un objet compagnon du même nom pour permettre la création d'objet sans le newmot clé.

Cette classe a une méthode apply surchargée: on prend un autre entier à ajouter et crée un nouvel objet avec la somme mise à jour, et un autre sans arguments pour obtenir la somme.

En Scala, tout objet avec une méthode apply peut être appelé comme une méthode, c'est-à-dire qu'il o.apply(x)peut être écrit en tant que o(x). Ceci est utilisé dans la bibliothèque standard pour les tableaux, les listes, les cartes et le Function1trait implémenté par les fonctions anonymes


2

Pyth, 19 octets

DhdDebR?bh+dbdR$end

Essayez-le en ligne!

Je suis impressionné par le fait que Javascript bat Pyth, mais là encore, Pyth n'est pas conçu pour passer des fonctions.


2

Perl 5, 36 octets

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

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

Qu'en est-il de cela -M5.016? Il semble que vous devriez pouvoir supprimer -M5.016, puis supprimer myet enregistrer quelques octets. Si c'est juste say, vous pouvez utiliser le drapeau à la -Eplace, qui ne s'active pas use strict, donc vous pouvez toujours laisser tomber le my.
Chris

@Chris tu as raison, il n'a pas besoin de la version 5.16, ma révision initiale l'a fait (en utilisant __SUB__) mais je l'ai changé avant de soumettre et je n'ai pas supprimé le passage relatif à la version 5.16. Je vais enlever ça. Je ne pense pas que laisser tomber myserait correct cependant.
Hobbs

(et non, je ne compte pas saydans le code, c'est à des fins d'illustration)
hobbs

1
Si vous supprimez mysans use strict, $nest implicitement une variable globale. C'est une mauvaise forme dans les scripts Perl appropriés, mais c'est assez courant dans les one-liners, et cela semble fonctionner ici.
Chris

2

Brain-Flak , 6 octets

En fait, je viens de remarquer que puisque le type de rapport est un format de retour valide, le 0 n'est pas nécessaire, ce qui permet d'économiser 2 octets:

({{}})

Essayez-le en ligne!

Soumission (s) originale (s), 8 octets

Utilise 0comme valeur spéciale:

({{}}{})

Essayez-le en ligne!

Explication

Étant donné les arguments a 1 , a 2 ,…, a n , 0, la pile ressemble initialement à ceci:

                                                       un n

                                                       

                                                       un 2

                                                       un 1

                                                       0

Le code continue ensuite, apparaît chaque a i , les accumule, le 0 les ajoute et pousse le résultat:

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

Solutions alternatives, 8 octets

Au lieu d'afficher le 0 et de l'ajouter à la somme, nous pouvons également échanger les piles puisque la bonne est initialement vide:

({{}}<>)

Essayez-le en ligne!

En utilisant le -rdrapeau, le 0 est en haut de la pile, nous pourrions donc le faire apparaître en premier:

({}{{}})

Essayez-le en ligne!

{}({{}})

Essayez-le en ligne!


Oh mon dieu ... Super!
Eugene D. Gubenkov

2

C (GCC), 83 octets

Mon premier golf C! Il existe deux autres solutions C, mais celle-ci est un peu différente. L'utilisation du préprocesseur est purement cosmétique. Cette approche a été discuté dans la réponse de Conor O'Brien ici .

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

La valeur terminale est zéro. La valeur de retour est une union, donc pour appeler le résultat, utilisez le champ f, et pour accéder à la valeur finale, utilisez le champ v, par exemple

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

Essayez-le en ligne

Limites

Une variable globale contient le total cumulé. Bien que cela soit explicitement interdit, la soumission prend en charge les appels répétés (le total est réinitialisé dans l'appel du terminal), ce qui semble être la raison de l'interdiction de l'état global.

Un pointeur sur fest stocké vers l'union retournée par l'intermédiaire du intmembre. Il est donc clair que ce n'est pas portable. Je ne sais pas si cela fonctionne sur GCC sur toutes les plateformes, ni sur Linux, ni sur x86, ni avec ELF ou ... Si quelqu'un connaît des détails à ce sujet, veuillez commenter ou envoyer un message!


2

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

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

0f

Essayez-le en ligne!

Termine en passant à zéro. Syntaxe d'appel:((0 f 1) 2) 0

-15 octets grâce à @ngn

A besoin ⎕IO←0

Tous les conseils de golf sont les bienvenus!


si vous pouvez utiliser 0 comme valeur de terminaison, le changement :If x<0de :If×xet échanger les « si » clauses et « else »
ngn

Derp. Je n'ai pas vu qu'il était dit "non positif"
Zacharý

connaissez-vous cette astuce? r←⍎condition⊃'else' 'then'
ngn


Je pensais que
c'était


1

Dyvil , 34 octets

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

Utilisation :

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

La fin ()peut être omis.

Explication :

Définit un opérateur de juxtaposition qui prend deux ints et les ajoute. Le paramètre ja la valeur par défaut 0pour prendre en charge l'appel sans arguments. Le 0dans les exemples ci-dessus n'est pas le nom, mais un littéral.


1

Julia v0.5 +, 52 octets

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

Appeler comme F. Cela pourrait probablement être beaucoup plus court en adoptant une méthode moins OO, mais j'aime toujours avoir la chance d'utiliser cet idiome.

Si on peut supposer qu '"au moins un appel sera passé avant l'appel de terminaison", la deuxième ligne peut être supprimée pour économiser 6 octets.



1

R, 40 octets

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

0 agit ici comme la valeur d'arrêt. Pour deux autres octets, nous pouvons l'omettre.

Le problème est que R manque d'un lambda intégré concis. Mais si nous en ajoutons un , nous pouvons obtenir le code à 26 octets :

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

(Oui, c'est valide R. Il faut juste importer.)


1

PHP, 44 octets

Une idée de @ user63956

Appel de terminaison 0

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

Version en ligne

Appel de terminaison avec NULLbesoin d'un càst [$i]à[+$i]

PHP, 47 octets

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

Version en ligne

PHP, 52 octets

Appel de terminaison NULLou toute autre valeur fausse en PHP

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

si le programme doit se terminer après la sortie, remplacer print$spar die("$s")+ 2 octets

Version en ligne


1
Je pense que la fonction devrait retourner (pas imprimer) $s. afin que vous puissiez faire quelque chose comme return$i?f:$sà la fin
Conor O'Brien

@ ConorO'Brien Je ne suis pas sûr, mais si votre pensée est bonne, vous pourriez économiser 5 octets. Merci
Jörg Hülsermann le

1
Quelques octets peuvent être enregistrés avec des variables superglobales: function f($i){return[$_GET[0]+=$i][$i]?:f;}.
user63956

@ user63956 une très bonne idée
Jörg Hülsermann

1

PowerShell, 86 octets

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

Essayez-le en ligne!

Code de test:

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

Sortie: 20


Très agréable. Bienvenue chez PPCG! Vous pouvez enregistrer un octet en faisant $n="$args"au lieu de $n=$args[0]. Cela ne fonctionnera pas sur l'autre $args[0], cependant, car vous obtiendrez la concaténation de chaînes plutôt que l'addition.
AdmBorkBork


1

Python, 69 octets

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

1
Je suppose que c'est du python? Vous devez indiquer la langue utilisée dans votre réponse.
corvus_192

Pouvez-vous essayer de jouer plus votre réponse au golf? Dans l'état actuel des choses, ce n'est pas très bien joué au golf.
Rɪᴋᴇʀ

1

Octave, 39 octets

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

* L’argument de l’appel de terminaison est 0.

Essayez-le en ligne!

* endfunctionrequis pour ajouter d'autres codes.


1

R, 54 52 octets

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

2 octets sauvés grâce à MickyT!

Semblable à l'une des réponses python. Ungolfed:

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

Fonctionne comme

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

1
Bon travail. Vous pouvez vous débarrasser des accolades internes autour de la clause if. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT

Je suis un peu perplexe de savoir pourquoi votre version «ungolfed» a return. returndans R n'est pas la même que dans d'autres langues, il effectue un abandon prématuré. Ne pas utiliser returnest idiomatique. D'autre part votre version non-golfée a toujours le golfé if.
Konrad Rudolph

@ KonradRudolph Le golf ifétait de la paresse, mais returnc'est juste pour la lisibilité - ça donne le même résultat avec ou sans return.
BLT

@BLT Hm. Je suis fermement convaincu que la gratuité dans R return diminue la lisibilité, car elle signale la mauvaise chose (sortie prématurée) et constitue un exemple de programmation culte de la cargaison .
Konrad Rudolph

Cool, j'ai encore appris quelque chose de nouveau. C'est une des raisons pour lesquelles je reviens sans cesse. Merci @ KonradRudolph, cette question de débordement de pile est également intéressante: stackoverflow.com/questions/11738823/…
BLT

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.