Карри произвольной длины


53

Напишите функцию, fкоторая принимает положительное целое число и возвращает функцию.

Возвращенная новая функция должна быть идентичной f. Однако, когда происходит «вызов завершения», fвместо этого следует возвращать сумму всех переданных целых чисел.

Например, g=f(4)(если fпервая функция) должна установить gдругую функцию. h=g(3)будет делать то же самое. Однако, когда вы вызываете hбез аргументов (см. Подробности ниже), он должен вывести 7, так как это сумма предыдущих аргументов функции. Другими словами f(3)(4)() == 7.

Обратите внимание, это не то же самое, что f(3,4)().

«Прекращение вызова» является одним из следующих вариантов (на ваш выбор):

  • вызов без аргументов
  • ноль в качестве аргумента
  • любое неположительное значение

Произвольное количество вызовов функций должно поддерживаться, предопределенного ограничения нет.

Гарантируется, что общая сумма не будет больше 1000.

Мы можем предположить, что перед «завершением вызова» сделан хотя бы один вызов.

Ваш код не должен использовать статические переменные для каждой программы, поэтому должна быть возможность многократно запускать эксперимент в одно и то же время выполнения и наблюдать одно и то же поведение.

Примеры:

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

4
@LuisMendo Обычно это означает, что f(4)возвращает новую функцию. Если эта новая функция вызывается без аргументов, она возвращается 4, но если она вызывается с другим аргументом, она снова возвращает новую функцию с той же семантикой, но с новым аргументом, добавленным к 4и так далее.
Мартин Эндер

6
@ LuisMendo Это действительно зависит от Юджина, но я думаю, что разрешение повторных вызовов значительно отнимает задачу, потому что интересная часть состоит не в создании функции с состоянием, а в выполнении функции более высокого порядка.
Мартин Эндер

6
@MartinEnder Это имеет большой смысл. Евгений, если это так, пожалуйста, измените формулировку задачи. Написать функцию, которую можно бесконечно вызывать, вовсе не говорит о том, что функция должна возвращать функцию
Луис Мендо,

4
Можем ли мы предположить, что одновременно будет только один экземпляр цепочки вызовов? Например нет q = f(2)(3); b = f(1)(2)(3); q(); b()?
Конор О'Брайен

3
Я только недавно подобрал Haskell, меня интересует, возможно ли это в Haskell. Сильная система типов заставляет меня думать, что это не так.
CAD97

Ответы:



21

Haskell (GHC), 118 байт

Это 98 байт для кода и 20 байт для флага компилятора GHC -XFlexibleInstances, который включает расширение системы типов.

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

Это определяет «функцию» f, которая может быть вызвана с произвольным числом целых чисел, за которыми следует единица (), после чего она возвращает целое число. Тип аннотации обязательны. Попробуйте онлайн!

объяснение

Чтобы заставить систему жестких типов Haskell разрешить это, требуется некоторое волшебство, а именно включение расширения GHC для гибких экземпляров классов типов. Как это работает, так fэто параметрически полиморфная функция, ограниченная ограничением класса типа: ее тип есть F a => Int -> a. Это означает, что fпринимает целое число и возвращает значение типа aдля любого типа, aкоторый принадлежит классу типов F. Fэто просто имя класса типов, который предоставляет функцию f; это объявлено в первой строке.

Следующие две строки являются двумя экземплярами Fдля разных типов a. Во второй строке указывается, что тип функций от ()целых принадлежит F(где ()это тип модуля, единственным членом которого является значение ()), а реализация - f n () = n; функция возвращает свой первый аргумент. В последней строке указывается, что если aпринадлежит F, то и тип функций из целых чисел в a: из функции f :: Int -> aмы можем сгенерировать другую функцию f :: Int -> Int -> a. Реализация такова f m n = f (m+n)(код использует комбинаторы, чтобы сделать его короче), где fслева - новый, а fсправа - старый. Это по сути даетfновый целочисленный аргумент, который добавляется к следующему. Несколько аргументов суммируются вместе следующим образом:

  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

fНа каждой линии имеет другой тип.

Функции на Haskell каррируются автоматически, поэтому, если вы дадите fтолько целые числа, вы получите функцию.


1
Может быть, я придираюсь, но это не совсем то, что требует задача. Вы определяете две (!) Функции, обе из которых вызваны f, а не одну функцию, которая выполняет свою работу. Тем не менее, это так близко, как вы можете получить в Haskell. Я не думаю, что можно решить задачу с помощью одной функции из-за строгой системы типов.
Nimi

3
@nimi Это определяет не две вызываемые функции f, а бесконечно много вызываемых функций f. (Один для каждого возможного числа аргументов.) Эти функции (из этого бесконечного семейства) имеют два вида определений, один вид, когда число аргументов равно нулю, и другой, когда это не так.
ShreevatsaR

@ShreevatsaR: я вижу два определения, f n()=nи f=(f.).(+)поэтому я бы назвал это определением двух функций.
Nimi

7
@nimi Есть два определения, но не две функции. Количество определений не обязательно должно быть числом функций. Например, вы можете определить факториальную функцию с двумя определениями g 0 = 1и g n = g (n-1) * n, где есть два определения, но только одна функция. Здесь у нас есть два определения, но бесконечно много функций. (Каждый из разных типов.)
ShreevatsaR

1
@nimi Кстати, ghciзагрузите вышеупомянутое и попробуйте :t f- он скажет f :: F a => Int -> a(имеется в виду, что если aэто экземпляр класса f, то fэто функция Int -> a). Таким образом, мы могли бы рассматривать это либо как одну функцию, либо как бесконечное множество, но, хотя у нее есть два вида определений (точно так же, как факториальная функция), я не вижу хорошей основы для того, чтобы считать ее двумя функциями.
ShreevatsaR

15

Python 2, 42 41 36 байт

Это решение никогда не будет переполнено, так как Python поддерживает целые числа произвольной точности. Ноль - это «особая ценность».

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

Попробуйте онлайн

Ungolfed:

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

14

C, 62 58 байт, пограничный конкурирующий

Сохранено 4 байта благодаря Кевину! (До сих пор не удаляем typedef, потому что это нужно для вызова.)

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

Функция для вызова есть f; Вы перестаете звонить и получаете результат, звоня с неположительным числом, таким как 0. Попробуйте использовать тестовые ремни онлайн!

Итак, насколько я могу судить, единственный способ «карри» функций с несколькими типами возвращаемых значений - это выполнить одно из следующих действий:

  1. Приведите результат к функции, чтобы сообщить компилятору, что вы хотите снова вызвать результат;
  2. или создайте тип union/, structкоторый имеет intподтипы и функцию / самоссылку.

Я попытался сделать (2), но это казалось немного противоречащим духу вопроса и, откровенно говоря, почти невозможно отменить. Таким образом, в соответствии с духом задачи, я выбрал вариант (1). Это требует приведения каждой возвращаемой функции в функцию, чтобы ее можно было использовать.

Этот «карри» синтаксис выглядит немного странно, но довольно похоже. Чтобы подражать f(21)(1), нужно было бы написать ((B)((B)f(21))(1))(0). Я определил Bтип как функцию, которая принимает целое число и возвращает указатель на функцию, которая принимает целое число. В развернутом виде это выглядит так:

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

Если вы говорите, что он заканчивается только на 0, вам понадобится приведение (что вы делаете в C, потому что C не может правильно определить функцию, которая возвращает себя), и вы оставляете очистку глобального между запусками вызывающей стороне (что Я думаю, что это вполне разумно), вы можете упростить все это до q;f(x){return x?(q+=x,f):q;}.
Кевин


1
@Kevin пока, согласно правилам сайта, функция должна быть многоразовой. Если бы я не обнулялся qпосле каждого запуска, то эта функция больше не могла бы использоваться
Конор О'Брайен,

Может быть, указатели на функции? Вы должны будете ссылаться каждый раз, но, возможно, стоит проверить
Downgoat

1
@ ConorO'Brien Я только что реализовал твой профсоюзный подход. Это длиннее этого, но не далеко.
Якоб

13

Mathematica, 25 байтов

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

Попробуйте онлайн! (Используя математику.)

Можно портировать ответ на JavaScript на три байта меньше, но я хотел представить более идиоматическое решение Mathematica. Это @всего лишь синтаксический сахар, который делает решение эквивалентным:

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

Так что да, идея в том, что в Mathematica вы не можете просто определить функцию, f[x_]но вы можете напрямую прикрепить значение к более сложному выражению, содержащему f, например f[x_], передав другой аргумент. Установив два определения для этого, мы можем получить желаемое поведение:

  • Первое определение объединяет один f[x][y]вызов f[x+y], тем самым потребляя один «вызов» и суммируя аргументы внутри. Это правило действует до тех пор, пока нас не оставят f[sum][].
  • Второе определение распаковывает этот последний случай, определяя всю вещь для оценки sum.

1
<3 символическое программирование
Джулиан Вольф

8

C ++, 72 байта

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

Это определяет тип, Fкоторый действует как запрошенная функция, и переменная fэтого типа для вызова. Он действителен для C ++ 11 и работает с онлайн-версиями GCC, clang, icc и VC ++.

Использование:

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

Объяснение:

После предварительной обработки и переформатирования это выглядит так:

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

Это обычно будет написано:

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

return a;и return {+a};делать то же самое, поскольку унарное +не меняет значение, и допускаются избыточные скобки вокруг возвращаемого значения. int mи int(m)сделать то же самое, поскольку допускаются избыточные скобки вокруг имени переменной, включая параметры функции. return {m+a};и return {int(m)+a};делать то же самое, так как приведение mиз intв intне меняет своего значения. Эти изменения operator()сближают две перегрузки по синтаксису, позволяя дважды вызывать одно определение макроса. Выбор правильного порядка для трех членов позволяет также intвключить в определение макроса первое слово следующей строки ( ).


1
Красивый. И не только решение для игры в гольф ... перегрузка, operator()чтобы сделать эту работу, была особенно крутой.
Рэй

6

Рубин, 23 байта

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

Использование:

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

6

C 104 96 байт

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

Использует метод по ссылке, которой поделилась @JulianWolf. Последний аргумент должен быть 0.

Попробуйте онлайн!


Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат .
Деннис

4

Math.JS, 38 байт

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

Позвони с f(number_a)(number_b)(...)(negative_number)

Если нам разрешено указать начальный вызов, 12 bytes ( f(x)=i(x,0)\n) может быть отброшено, и его можно вызвать сi(number_one,0)(number_two)(...)(negative_number)

Попробуй!

Explination

Латекс!

Как показано в приведенном выше примере LaTex, f(x)просто вызывает i(x,0), затем i(x,y)возвращает значение yif xменьше 0 или функцию j(z)=i(z,x+y), которая принимает один аргумент, который зацикливается. Добавление к стоимости y.


4

C 232 206 байт

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

Это, вероятно, может быть значительно улучшено, но должно служить подтверждением концепции, что C можно использовать без каких-либо языковых расширений *, чтобы решить эту проблему, вызывая без аргументов, а не с магическим значением.

* @hvd отметил, что, хотя это работает «из коробки» с использованием gcc, некоторая часть поведения не определена в стандарте C, что означает, что это не может быть переносимым. Используйте на свой риск!

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

Компиляция и запуск с gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingвыходами (после некоторых предупреждений)

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

«без каких-либо языковых расширений» - хитрость чередования gи hпродолжения цепочки макро-вызовов не гарантируется, так как не определено, gпоявляется ли следующий в контексте расширения первого g. C11 добавляет пример к 6.10.3.4, чтобы объяснить, что он не указан. (IIRC, препроцессор TenDRA - это тот, который не будет расширять его так, как вы хотите.) Кроме того, ни одна версия языка не поддерживает как пустые макро-аргументы, так и неявный int, поэтому действительная программа на Си не может использовать оба. :) Тем не менее, хороший ответ. Вы ищете в гольф это дальше?
HVd

@hvd: да, возможно, я вернусь к нему через пару дней и посмотрю, смогу ли я сыграть в гольф. Вы определенно правы, что это неопределенное поведение, но я думаю, что стандартная обработка здесь заключается в том, что языки определяются их реализацией, поэтому, пока он работает с gcc, я счастлив.
Джулиан Вольф

Я только что ответил на комментарий, который вы включили в свой ответ, что он не зависит от каких-либо языковых расширений. Да, даже с языковыми расширениями, это совершенно справедливо в качестве ответа здесь, не хотел предлагать иначе.
17

Ах, это определенно справедливо. Вы правы, что я должен оговорить, что, хотя никаких дополнительных флагов не требуется, это может быть не переносимым.
Джулиан Вольф

Вы можете проверить пустую строку с помощью *sвместо strlen(s). Строки C имеют неявную длину и заканчиваются на charзначение со значением 0. Хороший макрос, позволяющий звонить с / без аргумента!
Питер Кордес

4

8086 машинный код, 27 байт

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

Этот машинный код должен быть по адресу 0x100 и предполагает модель крошечного кода (cs = ds = es = ss). Расположение функции может быть изменено без затрат дополнительных байтов. Установка его со смещением 0сэкономит байт ( xor si,siвместо mov si, 0x100)

Обязательное соглашение о вызовах

Это предполагает, что вызывающий предварительно выделил как минимум 27 байтов в стеке. Он принимает число axи возвращает указатель на функцию bx. Вызов этого указателя с ax=0завершает цепочку и возвращает сумму в bx.
Итак, для первого звонка:

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

Затем для каждого последующего вызова:

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

Чтобы прекратить:

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

Ungolfed (прокомментировал разборку машинного кода):

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

После вызова этого с ненулевым AX, bx = spи буфер заполняется измененной копией машинного кода из function. 16-битный непосредственно в первой инструкции содержит сумму. (Это написано последней инструкцией перед ret.)

push di/ pop bxможно заменить на mov bx, di(до rep movsb), что упрощает, но не экономит.

Требование к вызывающей стороне передать указатель на буфер dst diпозволит сэкономить 4 байта по сравнению с вычислением его относительно sp.

Если сделать начальный адрес функции таким же, как размер функции, можно было бы сохранить byte ( mov cx, si).


Это было бы лучшим ответом, если бы вы включили разбор байтов машинного кода. Ответы машинного кода определенно нуждаются в неопрятной версии. например, используйте objdump -b binaryвместоhexdump -C
Питер Кордес

Обновлено с комментариями разборки. Возможная экономия: требуется, чтобы вызывающая сторона передавала указатель dst di(4 байта). Сделайте начальный адрес функции = размер: mov cx, siвместо mov cx, 0x1b.
Питер Кордес

2

C #, 62 байта

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

Для завершения вызова введите отрицательный номер, например

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

Я хотел бы заставить его работать, передавая nullили не указывая параметры до конца. Однако все способы, которые я пробовал, были намного длиннее
TheLethalCoder,

Вы можете использовать !mвместо m<0и передать nullили 0в качестве последнего параметра?
betseg

@betseg Нет, в C # Booleanможно использовать только a Boolean... Я пробовал, nullно он стал длиннее. Я хотел использовать, ??что означает, что если LHS равен null, то RHS, но, как мне нужно, если LHS не равен null, сделать это, иначе сделать RHS, я не смог.
TheLethalCoder

2

Скала, 58 символов

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

Попробуйте онлайн

Ungolfed:

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

Объяснение:

Этот код определяет case classвызываемый f с конструктором, принимающим int. Определите класс case, который будет генерировать методы equals, hashcode, toString и copy, а также сопутствующий объект с тем же именем для создания объекта без newключевого слова.

Этот класс имеет перегруженный метод apply: для добавления требуется другое целое число и создается новый объект с обновленной суммой, а другой - без аргументов для получения суммы.

В Scala любой объект с методом apply может быть вызван как метод, то есть o.apply(x)записан как o(x). Это используется в стандартной библиотеке для массивов, списков, карт и Function1признаков, реализованных анонимными функциями



2

Perl 5, 36 байт

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

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

Что по этому поводу требуется -M5.016? Кажется, вы должны быть в состоянии отбросить, -M5.016а затем также сбросить myи сохранить пару байтов. Если это просто say, вы можете использовать -Eвместо этого флаг , который не активируется use strict, поэтому вы все равно можете сбросить my.
Крис

@ Крис, вы правы, это не требует 5.16, моя первоначальная ревизия сделала (используя __SUB__), но я изменил это перед отправкой и не удалил бит о 5.16. Я удалю это. Я не думаю, что падение myбудет правильным, хотя.
Хоббс

(и нет, я не sayрассматриваю это как часть кода, это только для иллюстрации)
Хоббс,

1
Если вы удалите myбез use strict, $nэто неявно является глобальной переменной. Это плохая форма в правильных сценариях Perl, но это довольно распространено в однострочниках, и, похоже, здесь работает.
Крис

2

Brain-Flak , 6 байтов

На самом деле я только что заметил, что, поскольку ToS является допустимым возвращаемым форматом, выталкивание 0 на самом деле не нужно, что экономит 2 байта:

({{}})

Попробуйте онлайн!

Оригинал (ы), 8 байт

Используется 0как специальное значение:

({{}}{})

Попробуйте онлайн!

объяснение

С учетом аргументов a 1 , a 2 ,…, a n , 0 стек изначально выглядит так:

                                                       а н

                                                       

                                                       2

                                                       1

                                                       0

Затем код продолжается, выдает каждые a i , накапливает их, выдает 0, добавляет их и отправляет результат:

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

Альтернативные решения, 8 байт

Вместо того, чтобы ставить 0 и добавлять его к сумме, мы также можем поменять стеки, так как правый изначально пуст:

({{}}<>)

Попробуйте онлайн!

Используя -rфлаг, 0 находится на вершине стека, так что мы могли бы вытолкнуть его первым:

({}{{}})

Попробуйте онлайн!

{}({{}})

Попробуйте онлайн!


О боже мой ... Великолепно!
Евгений Дмитриевич Губенков

2

C (GCC), 83 байта

Мой первый C гольф! Есть несколько других C-решений, но это немного другое. Использование препроцессора чисто косметическое. Этот подход был впервые обсужден в ответе Конора О'Брайена здесь .

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

Терминальное значение равно нулю. Возвращаемое значение представляет собой объединение, поэтому для вызова результата используйте поле f, а для доступа к конечному значению используйте поле v, например

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

Попробуйте онлайн

Ограничения

Глобальная переменная содержит промежуточную сумму. Хотя это явно запрещено, отправка поддерживает повторные вызовы (общее значение сбрасывается при вызове терминала), что, по-видимому, и является причиной запрета глобального состояния.

Указатель на fсохраняется в возвращаемом объединении через intчлен, так что это явно не переносимо. Я не уверен, работает ли это на GCC на всех платформах, или только на Linux, или только на x86, или только с ELF или ... Если кто-нибудь знает какие-либо подробности об этом, пожалуйста, прокомментируйте или отправьте сообщение!


2

APL (Dyalog Classic) , 48 47 46 44 32 байта

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

0f

Попробуйте онлайн!

Завершается передачей в ноль. Синтаксис вызова:((0 f 1) 2) 0

-15 байт благодаря @ngn

требует ⎕IO←0

Любые советы по гольфу приветствуются!


если вы можете использовать 0 в качестве значения терминатора, измените :If x<0на :If×xи поменяйте местами предложения «if» и «else»
ngn

Derp. Я не видел, чтобы там говорилось «не позитивно»
Захари

ты знаешь этот трюк? r←⍎condition⊃'else' 'then'
августа


Мысль, что сказал 22 ...> _ <
Захари


1

Dyvil , 34 байта

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

Использование :

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

Трейлинг ()может быть опущен.

Пояснение :

Определяет оператор сопоставления, который берет два целых и добавляет их. Параметр jимеет значение 0по умолчанию для поддержки вызова без аргументов. В 0приведенных выше примерах это не имя, а литерал.


1

Юлия v0.5 +, 52 байта

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

Звоните как F. Вероятно, это можно было бы сделать намного короче, приняв метод менее ОО, но мне всегда нравится получать возможность использовать эту идиому.

Если можно предположить, что «перед завершающим вызовом будет сделан хотя бы один вызов», вторая строка может быть удалена для сохранения 6 байтов.



1

R, 40 байт

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

0 действует как стоп-значение здесь. Еще два байта мы можем опустить.

Проблема в том, что R не хватает краткой встроенной лямбды. Но если мы добавим один , мы можем получить код до 26 байтов :

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

(Да, это действительно R. Это просто нужно импортировать.)


1

PHP, 44 байта

Идея от @ user63956

Завершение вызова 0

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

Онлайн версия

Прекращение вызова с NULLнеобходимостью гипса [$i]в[+$i]

PHP, 47 байт

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

Онлайн версия

PHP, 52 байта

Завершение вызова NULLили любое другое значение, которое является ложным в PHP

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

если программа должна завершиться после выхода, заменить print$sна die("$s")+ 2 байта

Онлайн версия


1
Я думаю, что функция должна вернуть (не печатать) $s. так что вы могли бы сделать что-то вроде return$i?f:$sв конце
Конор О'Брайен

@ ConorO'Brien Я не уверен, но если ваше мышление правильно, оно может сэкономить 5 байт. Спасибо
Jörg Hülsermann

1
Несколько байт могут быть сохранены с суперглобальными переменными function f($i){return[$_GET[0]+=$i][$i]?:f;}.
user63956

@ user63956 очень хорошая идея
Йорг Хюльсерманн

1

PowerShell, 86 байт

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

Попробуйте онлайн!

Тестовый код:

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

Выход: 20


Очень хорошо. Добро пожаловать в PPCG! Вы можете сохранить байт, выполнив $n="$args"вместо $n=$args[0]. Однако с другой стороны это не сработает $args[0], потому что тогда вы получите конкатенацию строк, а не сложение.
AdmBorkBork


1

Python, 69 байт

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

1
Я предполагаю, что это питон? Вы должны указать язык, используемый в вашем ответе.
corvus_192

Можете ли вы попытаться ответить на ваш вопрос? В нынешнем виде игра не очень удачная.
Rɪᴋᴇʀ

1

Октава, 39 байт

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

* Аргументом завершения вызова является 0.

Попробуйте онлайн!

* endfunctionтребуется добавить некоторые другие коды.


1

R, 54 52 байта

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

Благодаря MickyT сэкономлено 2 байта!

Похоже на один из ответов питона. Ungolfed:

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

Работает как

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

1
Хорошо сделано. Вы можете избавиться от внутренних скобок вокруг предложения if. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT

Я немного озадачен, почему ваша версия «без гольфа» имеет return. returnв R это не то же самое, что в других языках, он выполняет преждевременную отмену. Не использовать returnэто идиоматично. С другой стороны, в вашей версии без гольфа все еще есть гольф if.
Конрад Рудольф

@KonradRudolph Гольф ifбыл лень, но returnтолько для удобства чтения - он дает тот же результат с или без return.
BLT

@BLT Хм. Я твердо убежден, что безвозмездность в R return снижает читабельность, поскольку сигнализирует о неправильной вещи (преждевременный выход) и является примером программирования культового груза .
Конрад Рудольф

Круто, я снова узнал что-то новое. Это одна из причин, почему я продолжаю возвращаться. Спасибо @KonradRudolph, также интересен этот вопрос переполнения стека: stackoverflow.com/questions/11738823/…
BLT

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.