Cà ri dài tùy ý


53

Viết một hàm, flấy một số nguyên dương và trả về một hàm.

Hàm mới được trả về phải giống hệt f. Tuy nhiên, khi "cuộc gọi chấm dứt" xảy ra, fthay vào đó sẽ trả về tổng của tất cả các số nguyên được thông qua.

Ví dụ: g=f(4)(nếu flà chức năng đầu tiên) nên đặt thành gchức năng khác. h=g(3)sẽ làm như vậy Tuy nhiên, khi bạn gọi hmà không có đối số (xem bên dưới để biết chi tiết), nó sẽ xuất 7, vì đó là tổng của các đối số hàm trước đó. Đặt một cách khác , f(3)(4)() == 7.

Hãy lưu ý điều này không giống như f(3,4)().

"Cuộc gọi chấm dứt" là một trong các tùy chọn sau (lựa chọn của bạn):

  • gọi đối số w / o
  • null làm đối số
  • bất kỳ giá trị không tích cực

Số lượng tùy ý của các cuộc gọi chức năng nên được hỗ trợ, không có giới hạn được xác định trước.

Nó được đảm bảo rằng tổng số tiền sẽ không lớn hơn 1000.

Chúng tôi có thể giả định rằng có ít nhất một cuộc gọi được thực hiện trước khi "cuộc gọi chấm dứt".

Mã của bạn không nên sử dụng các biến tĩnh, theo chương trình, do đó có thể chạy thử nghiệm nhiều lần trong cùng một thời gian chạy và quan sát chính xác cùng một hành vi.

Ví dụ:

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

4
@LuisMendo Nó thường có nghĩa là f(4)trả về một chức năng mới. Nếu hàm mới đó được gọi mà không có đối số, nó sẽ trả về 4, nhưng nếu nó được gọi với một đối số khác thì nó sẽ lại trả về một hàm mới có cùng ngữ nghĩa nhưng với đối số mới được thêm vào 4, v.v.
Martin Ender

6
@LuisMendo Điều đó thực sự tùy thuộc vào Eugene, nhưng tôi nghĩ rằng việc cho phép các cuộc gọi lặp đi lặp lại sẽ giúp giảm đáng kể thách thức, bởi vì phần thú vị không phải là tạo ra một chức năng trạng thái mà là tạo ra một chức năng bậc cao hơn.
Martin Ender

6
@MartinEnder Điều đó rất có ý nghĩa. Eugene, nếu đó là ý định, xin vui lòng thay đổi từ ngữ của thách thức. Viết một hàm có thể được gọi vô hạn hoàn toàn không gợi ý rằng hàm này sẽ trả về một hàm
Luis Mendo

4
Chúng ta có thể giả định rằng sẽ chỉ có một phiên bản của chuỗi cuộc gọi tại một thời điểm không? Vd không q = f(2)(3); b = f(1)(2)(3); q(); b()?
Conor O'Brien

3
Vừa mới nhặt được Haskell, tôi quan tâm đến việc điều này có thể xảy ra ở Haskell không. Hệ thống loại mạnh khiến tôi nghĩ rằng nó có thể không.
CAD97

Câu trả lời:


49

JavaScript (ES6), 18 byte

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

Vượt qua một giá trị giả để lấy tổng. Số không có thể được cho phép với chi phí là 2 byte.

Dùng thử trực tuyến

Ung dung:

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

Rực rỡ trình!
Eugene D. Gubenkov

21

Haskell (GHC), 118 byte

Đây là 98 byte cho mã và 20 byte cho cờ trình biên dịch GHC -XFlexibleInstances, cho phép mở rộng hệ thống loại.

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

Điều này định nghĩa một "hàm" f, có thể được gọi với một số nguyên tùy ý theo sau là đơn vị (), sau đó nó trả về một số nguyên. Chú thích loại được yêu cầu. Hãy thử trực tuyến!

Giải trình

Buộc hệ thống loại nghiêm ngặt của Haskell cho phép điều này đòi hỏi một số phép thuật, cụ thể là, cho phép tiện ích mở rộng GHC cho các trường hợp kiểu chữ linh hoạt. Làm thế nào điều này hoạt động là fmột hàm đa hình tham số bị hạn chế bởi một ràng buộc lớp loại: loại của nó là F a => Int -> a. Điều này có nghĩa là flấy một số nguyên và trả về một giá trị của loại a, cho bất kỳ loại anào thuộc về kiểu chữ F. Fchỉ là tên của kiểu chữ cung cấp hàm f; nó được tuyên bố trên dòng đầu tiên.

Hai dòng tiếp theo là hai trường hợp Fcho các loại khác nhau a. Dòng thứ hai nói rằng loại hàm từ ()đến số nguyên thuộc về F(trong đó ()loại đơn vị có thành viên duy nhất là giá trị ()) và việc thực hiện là f n () = n; hàm trả về đối số đầu tiên của nó. Dòng cuối cùng nói rằng nếu athuộc về F, thì loại hàm từ số nguyên đến a: từ một hàm f :: Int -> achúng ta có thể tạo một hàm khác f :: Int -> Int -> a. Việc thực hiện là f m n = f (m+n)(mã sử dụng các tổ hợp để làm cho nó ngắn hơn), trong đó fbên trái là cái mới và fbên phải là cái cũ. Điều này về cơ bản mang lạifmột đối số nguyên mới, được thêm vào đối số tiếp theo. Nhiều đối số được tóm tắt cùng nhau như thế này:

  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

Trên fmỗi dòng có một loại khác nhau.

Các hàm Haskell được tự động xử lý, vì vậy nếu bạn fchỉ cung cấp số nguyên, bạn sẽ có được một hàm.


1
Có thể tôi đang bịp bợm, nhưng đó không phải là điều mà thách thức yêu cầu. Bạn đang xác định hai hàm (!), Cả hai được gọi f, không phải là một hàm duy nhất thực hiện công việc. Tuy nhiên, đây là gần như bạn có thể nhận được trong Haskell. Tôi không nghĩ có thể giải quyết nhiệm vụ bằng một chức năng duy nhất vì hệ thống loại nghiêm ngặt.
nimi

3
@nimi Điều này định nghĩa không phải hai hàm được gọi f, nhưng vô số hàm được gọi f. (Một cho mỗi số lượng đối số có thể.) Các hàm này (từ họ vô hạn này) có hai loại định nghĩa, một loại khi số lượng đối số bằng 0 và một loại khác khi không có.
ShreevatsaR

@ShreevatsaR: Tôi thấy hai định nghĩa f n()=nf=(f.).(+)vì vậy tôi gọi nó là định nghĩa hai hàm.
nimi

7
@nimi Có hai định nghĩa, nhưng không phải hai chức năng. Số lượng định nghĩa không cần phải là số lượng hàm. Ví dụ: bạn có thể định nghĩa hàm giai thừa với hai định nghĩa g 0 = 1g n = g (n-1) * n, trong đó có hai định nghĩa nhưng chỉ có một hàm. Ở đây chúng tôi có hai định nghĩa nhưng vô số chức năng. (Mỗi loại khác nhau.)
ShreevatsaR

1
@nimi BTW ghcitải ở trên và thử :t f- nó sẽ nói f :: F a => Int -> a(có nghĩa là nếu alà một thể hiện của lớp f, thì đó flà một hàm Int -> a). Vì vậy, chúng ta có thể coi đây là một hàm hoặc vô số, nhưng mặc dù nó có hai loại định nghĩa (giống như hàm giai thừa) Tôi không thấy bất kỳ cơ sở tốt nào để coi nó là hai hàm.
ShreevatsaR

15

Python 2, 42 41 36 byte

Giải pháp này sẽ không bao giờ có tràn, vì Python hỗ trợ các số nguyên có độ chính xác tùy ý. Không là "giá trị đặc biệt".

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

Dùng thử trực tuyến

Ung dung:

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

14

C, 62 58 byte, cạnh tranh biên giới

Đã lưu 4 byte nhờ Kevin! (Vẫn không xóa typedef vì đó là thứ cần thiết để được gọi.)

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

Chức năng để gọi là f; bạn ngừng gọi nó và nhận được kết quả bằng cách gọi nó với một số không tích cực như thế nào 0. Hãy thử khai thác trực tuyến!

Vì vậy, theo như tôi có thể nói, cách duy nhất để "cà ri" các hàm có nhiều kiểu trả về là thực hiện một trong các cách sau:

  1. Truyền kết quả cho một hàm để báo cho trình biên dịch mà bạn muốn gọi lại kết quả;
  2. hoặc tạo một union/ structloại có các kiểu con intvà hàm / tự tham chiếu.

Tôi đã thử làm (2), nhưng nó có vẻ hơi trái với tinh thần của câu hỏi và, thật lòng mà nói, gần như không thể làm được. Vì vậy, để phù hợp với tinh thần của thử thách, tôi đã chọn phương án (1). Điều này đòi hỏi phải truyền từng hàm được trả về thành một hàm, nó có thể được sử dụng.

Cú pháp "currying" này có vẻ hơi kỳ lạ, nhưng khá giống nhau. Để thi đua f(21)(1), người ta sẽ phải viết ((B)((B)f(21))(1))(0). Tôi đã định nghĩa Bkiểu là một hàm lấy một số nguyên và trả về một con trỏ tới một hàm lấy một số nguyên. Mở rộng, nó trông giống như:

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

Nếu bạn nói rằng nó chỉ kết thúc bằng 0, thì bạn sẽ yêu cầu truyền (bạn thực hiện trong C vì C không thể xác định đúng chức năng tự trả về) và bạn để lại toàn cầu giữa các lần chạy cho người gọi (mà Tôi nghĩ là hoàn toàn hợp lý), bạn có thể đơn giản hóa toàn bộ q;f(x){return x?(q+=x,f):q;}.
Kevin


1
@Kevin chưa, theo quy định của trang web, một chức năng phải được sử dụng lại. Nếu tôi không về 0 qsau mỗi lần chạy, thì chức năng đó sẽ không còn sử dụng được nữa
Conor O'Brien

Có thể chức năng con trỏ? Bạn sẽ phải
hủy

1
@ ConorO'Brien Tôi vừa thực hiện phương pháp hợp nhất của bạn. Nó dài hơn cái này, nhưng nó không còn xa.
Jakob

13

Toán học, 25 byte

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

Hãy thử trực tuyến! (Sử dụng toán học.)

Có thể thực hiện ít hơn ba byte bằng cách chuyển câu trả lời JavaScript, nhưng tôi muốn trình bày một giải pháp Mathicala thành ngữ hơn. Đây @chỉ là một chút đường cú pháp, làm cho giải pháp tương đương với:

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

Vì vậy, ý tưởng là trong Mathicala, bạn không thể chỉ định nghĩa một hàm f[x_]nhưng bạn có thể trực tiếp đính kèm một giá trị vào một biểu thức phức tạp hơn có chứa f, ví dụ như f[x_]được thông qua một đối số khác. Bằng cách thiết lập hai định nghĩa cho điều này, chúng ta có thể có được hành vi mong muốn:

  • Định nghĩa đầu tiên thu gọn một f[x][y]cuộc gọi vào f[x+y], do đó tiêu thụ một "cuộc gọi" và thêm các đối số bên trong. Quy tắc này áp dụng cho đến khi chúng tôi còn lại với f[sum][].
  • Định nghĩa thứ hai giải nén trường hợp cuối cùng này bằng cách xác định toàn bộ điều cần đánh giá sum.

1
<3 chương trình biểu tượng
Julian Wolf

8

C ++, 72 byte

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

Điều này xác định một loại Fhoạt động như chức năng được yêu cầu và một biến fcủa loại đó để gọi. Nó hợp lệ kể từ C ++ 11 và hoạt động với các phiên bản trực tuyến của GCC, clang, icc và VC ++.

Sử dụng:

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

Giải trình:

Sau khi tiền xử lý và định dạng lại, có vẻ như:

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

Điều này thường sẽ được viết:

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

return a;return {+a};làm điều tương tự, vì unary +không thay đổi giá trị và cho phép các dấu ngoặc thừa xung quanh giá trị trả về. int mint(m)làm điều tương tự, vì các dấu ngoặc đơn thừa xung quanh một tên biến được cho phép, bao gồm các tham số hàm. return {m+a};return {int(m)+a};làm điều tương tự, như một diễn viên mtừ intđến intkhông thay đổi giá trị của nó. Những thay đổi này giúp hai operator()cú pháp quá tải gần hơn theo cú pháp, cho phép một định nghĩa macro duy nhất được gọi hai lần. Chọn đúng thứ tự cho ba thành viên cho phép từ đầu tiên của dòng tiếp theo ( int) cũng được bao gồm trong định nghĩa vĩ mô.


1
Đẹp. Và không chỉ là giải pháp chơi gôn ... quá tải operator()để làm cho công việc này đặc biệt tuyệt vời.
Ray Toal

6

Ruby, 23 byte

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

Sử dụng:

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

6

C, 104 96 byte

#define a(i)s(i)|b
#define b(i)u(i)|c
#define c(i)u(i)|b
b,c,d;s(i){b=c=i;i=d;}u(i){c=b+=i;i=d;}

Sử dụng phương pháp từ liên kết mà @JulianWolf đã chia sẻ. Đối số cuối cùng phải là 0.

Hãy thử trực tuyến!


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Dennis

4

Math.JS, 38 byte

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

Gọi nó với f(number_a)(number_b)(...)(negative_number)

Nếu chúng tôi được phép chỉ định cuộc gọi ban đầu, 12 byte ( f(x)=i(x,0)\n) có thể bị hủy và có thể được gọi bằngi(number_one,0)(number_two)(...)(negative_number)

Thử nó!

Giải thích

Mủ cao su!

Như được hiển thị trong LaTex ở trên, f(x)chỉ cần gọi i(x,0), sau đó, i(x,y)trả về giá trị yif xnhỏ hơn 0 hoặc hàm j(z)=i(z,x+y), nhận một đối số, vòng lặp. Thêm vào giá trị của y.


4

C, 232 206 byte

#include<string.h>
#include<stdlib.h>
#define f(X)s(""#X)?0:g
#define g(X)u(""#X)?0:h
#define h(X)u(""#X)?0:g
g=0,h=0;s(char*s){g=h=atoi(s);return 0;}u(char*s){char*a=strlen(s)?s:"0";g=h+=atoi(a);return 0;}

Điều này có thể có thể được đánh golf đáng kể, nhưng nên đóng vai trò là bằng chứng của khái niệm rằng C có thể được sử dụng, mà không cần bất kỳ phần mở rộng ngôn ngữ nào *, để giải quyết vấn đề này bằng cách gọi mà không cần đối số thay vì bằng giá trị ma thuật.

* @hvd đã lưu ý rằng, trong khi điều này hoạt động tốt khi sử dụng gcc, một số hành vi không được xác định trong tiêu chuẩn C, có nghĩa là điều này có thể không khả chuyển. Sử dụng có nguy cơ của riêng bạn!

Ung dung:

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

Biên dịch và chạy với gcc arbitrary-length-currying.c -o arbitrary-length-currying && ./arbitrary-length-curryingđầu ra (sau một số cảnh báo)

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

"không có bất kỳ tiện ích mở rộng ngôn ngữ nào" - Thủ thuật xen kẽ giữa ghtiếp tục một chuỗi các yêu cầu vĩ mô không được đảm bảo để hoạt động, vì nó không xác định liệu tiếp theo có gxuất hiện trong bối cảnh mở rộng đầu tiên hay không g. C11 thêm một ví dụ vào 6.10.3.4 để đánh vần rằng nó không được chỉ định. (IIRC, bộ tiền xử lý của TenDRA là một bộ xử lý sẽ không mở rộng nó theo cách bạn muốn.) Ngoài ra, không có phiên bản ngôn ngữ nào hỗ trợ cả đối số macro trống và int ẩn, vì vậy một chương trình C hợp lệ không thể sử dụng cả hai. :) Tuy nhiên, câu trả lời tốt đẹp. Bạn đang tìm cách để chơi golf hơn nữa?
hvd

@hvd: yeah, có lẽ sẽ quay lại sau vài ngày nữa và xem liệu tôi có thể đánh nó xuống không. Bạn chắc chắn đúng rằng đây là hành vi không xác định, nhưng tôi nghĩ rằng cách xử lý tiêu chuẩn ở đây là ngôn ngữ được xác định bởi việc triển khai của chúng, miễn là nó hoạt động với gcc tôi rất vui.
Julian Wolf

Tôi chỉ giải quyết bình luận mà bạn đưa vào câu trả lời của bạn rằng nó không dựa vào bất kỳ phần mở rộng ngôn ngữ nào. Có, ngay cả với các phần mở rộng ngôn ngữ, nó hoàn toàn hợp lệ như một câu trả lời ở đây, không có nghĩa là đề xuất khác.
hvd

Ah, điều đó chắc chắn công bằng. Bạn đúng rằng tôi nên quy định rằng, trong khi không yêu cầu thêm cờ, điều này có thể không thể mang theo được.
Julian Wolf

Bạn có thể kiểm tra chuỗi trống *sthay vì strlen(s). Các chuỗi C có độ dài ngầm định, được kết thúc bằng a charcó giá trị 0. Hack macro đẹp để cho phép cuộc gọi có / không có đối số!
Peter Cordes

4

Mã máy 8086, 27 byte

00000000  bb 00 00 85 c0 74 13 01  d8 be 00 01 89 e7 47 47  |.....t........GG|
00000010  57 b9 1b 00 f3 a4 5b 89  47 01 c3                 |W.....[.G..|
0000001b

Mã máy này phải ở địa chỉ 0x100 và giả sử mô hình mã nhỏ (cs = ds = es = ss). Tuy nhiên, vị trí chức năng có thể được thay đổi mà không tốn thêm byte. Đặt nó ở offset 0sẽ tiết kiệm một byte ( xor si,sithay vì mov si, 0x100)

Quy ước gọi điện yêu cầu

Điều này giả sử người gọi đã phân bổ trước ít nhất 27 byte trên ngăn xếp. Nó nhận một số trong axvà trả về một con trỏ hàm trong bx. Gọi con trỏ này bằng cách ax=0kết thúc chuỗi và trả về tổng bx.
Vì vậy, cho cuộc gọi đầu tiên:

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

Sau đó, cho mỗi cuộc gọi tiếp theo:

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

Để chấm dứt:

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

Ungolfed (nhận xét tháo gỡ mã máy):

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

Sau khi gọi điều này với AX khác không, bx = spvà bộ đệm chứa đầy một bản sao sửa đổi của mã máy từ function. 16 bit ngay lập tức trong hướng dẫn đầu tiên giữ tổng số. (Nó được viết bởi hướng dẫn cuối cùng trướcret .)

push di/ pop bxcó thể được thay thế bằng mov bx, di(trướcrep movsb ), làm cho nó đơn giản hơn nhưng không tiết kiệm.

Yêu cầu người gọi chuyển một con trỏ đến bộ đệm dst disẽ tiết kiệm được 4 byte so với việc tính toán nó so vớisp .

Làm cho hàm bắt đầu địa chỉ giống như kích thước hàm sẽ tiết kiệm một byte ( mov cx, si).


Đây sẽ là một câu trả lời tốt hơn nếu bạn bao gồm việc tháo gỡ các byte mã máy. câu trả lời mã máy chắc chắn cần một phiên bản không có căn cứ. ví dụ: sử dụng objdump -b binarythay vìhexdump -C
Peter Cordes

Cập nhật với nhận xét tháo gỡ. Tiết kiệm có thể: yêu cầu người gọi vượt qua một con trỏ dst trong di(4 byte). Tạo hàm bắt đầu địa chỉ = size: mov cx, sithay vì mov cx, 0x1b.
Peter Cordes

2

C #, 62 byte

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

Để kết thúc cuộc gọi trong một số âm, vd

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

Tôi muốn làm cho nó hoạt động bằng cách chuyển vào nullhoặc không có tham số nào kết thúc. Tuy nhiên, tất cả các cách tôi đã thử dài hơn rất nhiều
TheLethalCoder

Bạn có thể sử dụng !mthay vì m<0và vượt qua nullhoặc 0là tham số cuối cùng?
betseg

@betseg Không có trong C # chỉ Booleancó thể được sử dụng như một Boolean... Tôi đã thử với nullnhưng nó chỉ dài hơn. Tôi muốn sử dụng ??điều đó có nghĩa là nếu LHS không làm RHS, nhưng vì tôi cần nếu LHS không null thì làm điều này khác với RHS, tôi không thể.
TheLethalCoder

2

Scala, 58 ký tự

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

Dùng thử trực tuyến

Ung dung:

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

Giải trình:

Mã này định nghĩa một case classf được gọi với hàm tạo lấy int. Xác định một lớp trường hợp sẽ tạo ra các phương thức bằng, mã băm, toString và sao chép và một đối tượng đồng hành có cùng tên để cho phép tạo đối tượng mà không cần newtừ khóa.

Lớp này có một phương thức áp dụng quá tải: Một người lấy một số nguyên khác để thêm và tạo một đối tượng mới với tổng được cập nhật và một không có đối số để lấy tổng.

Trong Scala, bất kỳ đối tượng nào có phương thức áp dụng đều có thể được gọi như phương thức, o.apply(x)có thể được viết là o(x). Điều này được sử dụng trong thư mục tiêu chuẩn cho mảng, danh sách, bản đồ và Function1đặc điểm được thực hiện bởi các hàm ẩn danh


2

Bình thường, 19 byte

DhdDebR?bh+dbdR$end

Hãy thử trực tuyến!

Tôi ấn tượng rằng Javascript đánh bại Pyth, nhưng một lần nữa Pyth không được thiết kế để truyền các chức năng.


2

Perl 5, 36 byte

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

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

Điều này đòi hỏi -M5.016gì? Có vẻ như bạn sẽ có thể thả -M5.016và sau đó thả myvà lưu một vài byte. Nếu chỉ say, bạn có thể sử dụng cờ -Ethay thế, không kích hoạt use strict, vì vậy bạn vẫn có thể thả cờ my.
Chris

@Chris bạn nói đúng, nó không cần 5.16, bản sửa đổi ban đầu của tôi đã (sử dụng __SUB__) nhưng tôi đã thay đổi điều đó trước khi gửi và không xóa bit về 5.16. Tôi sẽ xóa nó. Tôi không nghĩ rằng thả mysẽ là chính xác mặc dù.
hobbs

(và không, tôi không tính saylà một phần của mã, nó chỉ nhằm mục đích minh họa)
hobbs

1
Nếu bạn loại bỏ mymà không cóuse strict , $nthì hoàn toàn là một biến toàn cục. Đó là hình thức xấu trong các tập lệnh perl thích hợp, nhưng nó khá phổ biến trong một lớp và nó dường như hoạt động ở đây.
Chris

2

Brain-Flak , 6 byte

Trên thực tế tôi chỉ nhận thấy rằng ToS là định dạng trả về hợp lệ xuất hiện 0 nên không thực sự cần thiết, giúp tiết kiệm 2 byte:

({{}})

Hãy thử trực tuyến!

Trình gốc, 8 byte

Sử dụng 0như giá trị đặc biệt:

({{}}{})

Hãy thử trực tuyến!

Giải trình

Với những lập luận một 1 , một 2 , ..., một n , 0 ngăn xếp ban đầu trông như thế này:

                                                       một n

                                                       

                                                       một 2

                                                       một 1

                                                       0

Sau đó, mã tiếp tục, bật mỗi a i , tích lũy chúng, bật 0 thêm chúng và đẩy kết quả:

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

Giải pháp thay thế, 8 byte

Thay vì bật 0 và thêm nó vào tổng, chúng ta cũng có thể hoán đổi các ngăn xếp vì bên phải ban đầu trống:

({{}}<>)

Hãy thử trực tuyến!

Sử dụng -rcờ số 0 nằm trên đỉnh của ngăn xếp, vì vậy chúng tôi có thể bật nó trước:

({}{{}})

Hãy thử trực tuyến!

{}({{}})

Hãy thử trực tuyến!


Ôi trời ơi ... Tuyệt vời!
Eugene D. Gubenkov

2

C (GCC), 83 byte

Golf C đầu tiên của tôi! Có một vài giải pháp C khác, nhưng cách này hơi khác một chút. Sử dụng tiền xử lý hoàn toàn là mỹ phẩm. Cách tiếp cận này lần đầu tiên được thảo luận trong câu trả lời của Conor O'Brien tại đây .

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

Giá trị đầu cuối bằng không. Giá trị trả về là một liên kết, vì vậy để gọi kết quả, sử dụng trường fvà để truy cập giá trị cuối cùng, hãy sử dụng trường v, vd

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

Dùng thử trực tuyến

Hạn chế

Một biến toàn cục giữ tổng số chạy. Mặc dù điều này không được phép rõ ràng, việc đệ trình không hỗ trợ các lệnh được lặp đi lặp lại (tổng số được đặt lại trong lệnh gọi thiết bị đầu cuối), đây dường như là lý do cho lệnh cấm đối với trạng thái toàn cầu.

Một con trỏ fđược lưu trữ cho liên minh được trả về thông qua intthành viên, vì vậy đây rõ ràng là không thể mang theo được. Tôi không chắc liệu điều này có hoạt động trên GCC trên tất cả các nền tảng hay chỉ trên Linux hoặc chỉ trên x86 hoặc chỉ với ELF hoặc ... Nếu có ai biết bất kỳ chi tiết nào về việc này, vui lòng bình luận hoặc gửi tin nhắn!


2

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

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

0f

Hãy thử trực tuyến!

Chấm dứt bằng cách vượt qua trong không. Cú pháp cuộc gọi:((0 f 1) 2) 0

-15 byte nhờ @ngn

Đòi hỏi ⎕IO←0

Bất kỳ lời khuyên chơi golf đều được chào đón!


nếu bạn có thể sử dụng 0 làm giá trị của bộ kết thúc, hãy đổi :If x<0thành :If×xvà hoán đổi các mệnh đề "nếu" và "khác"
ngn

Derp. Tôi không thấy nó nói "không tích cực"
Zacharý

Bạn có biết thủ thuật này? r←⍎condition⊃'else' 'then'
ngn


Nghĩ rằng đã nói 22 ...> _ <
Zacharý


1

Dyvil , 34 byte

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

Cách sử dụng :

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

Các dấu vết ()có thể được bỏ qua.

Giải thích :

Xác định một toán tử juxtap vị trí có hai int và thêm chúng. Tham số jcó giá trị mặc định 0để hỗ trợ cuộc gọi mà không cần đối số. Trong 0các ví dụ trên không phải là tên, mà là một nghĩa đen.


1

Julia v0.5 +, 52 byte

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

Gọi như F . Điều này có lẽ có thể được thực hiện ngắn hơn rất nhiều bằng cách áp dụng một phương pháp OO ít hơn, nhưng tôi luôn muốn có cơ hội sử dụng thành ngữ này.

Nếu có thể giả định rằng "ít nhất một cuộc gọi sẽ được thực hiện trước cuộc gọi kết thúc", dòng thứ hai có thể được xóa để lưu 6 byte.



1

R, 40 byte

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

0 đóng vai trò là giá trị dừng ở đây. Đối với hai byte nữa, chúng ta có thể bỏ qua nó.

Vấn đề là R thiếu lambda tích hợp sẵn. Nhưng nếu chúng ta thêm một , chúng ta có thể nhận được mã tới 26 byte :

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

(Vâng, đó là hợp lệ R. Nó chỉ cần nhập khẩu.)


1

PHP, 44 byte

Một ý tưởng từ @ user63956

Cuộc gọi chấm dứt 0

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

Phiên bản trực tuyến

Gọi chấm dứt với NULLcần một dàn diễn viên [$i]đến[+$i]

PHP, 47 byte

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

Phiên bản trực tuyến

PHP, 52 byte

Cuộc gọi chấm dứt NULLhoặc bất kỳ giá trị nào khác là sai trong PHP

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

nếu chương trình phải chấm dứt sau khi Đầu ra thay thế print$sbằng die("$s")+ 2 byte

Phiên bản trực tuyến


1
Tôi nghĩ rằng chức năng sẽ trở lại (không in) $s. vì vậy bạn có thể làm một cái gì đó giống như return$i?f:$sở cuối
Conor O'Brien

@ ConorO'Brien Tôi không chắc nhưng nếu Suy nghĩ của bạn đúng thì có thể tiết kiệm 5 Byte Cảm ơn bạn
Jörg Hülsermann

1
Một vài byte có thể được lưu với các biến siêu lớp : function f($i){return[$_GET[0]+=$i][$i]?:f;}.
dùng63956

@ user63956 một ý tưởng rất hay
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()}

Hãy thử trực tuyến!

Mã kiểm tra:

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

Đầu ra: 20


Rất đẹp. Chào mừng đến với PPCG! Bạn có thể lưu một byte bằng cách làm $n="$args"thay vì $n=$args[0]. $args[0]Mặc dù vậy, nó sẽ không hoạt động , bởi vì sau đó bạn sẽ có được nối chuỗi thay vì bổ sung.
admBorkBork


1

Python, 69 byte

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

1
Tôi cho rằng đây là trăn? Bạn nên nói ngôn ngữ được sử dụng trong câu trả lời của bạn.
corvus_192

Bạn có thể cố gắng để chơi golf câu trả lời của bạn nhiều hơn? Khi nó đứng, nó không phải là golf tốt.
Rɪᴋᴇʀ

1

Octave, 39 byte

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

* Đối số của cuộc gọi kết thúc là 0.

Hãy thử trực tuyến!

* endfunctioncần thiết để thêm một số mã khác.


1

R, 54 52 byte

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

Đã lưu 2 byte nhờ MickyT!

Tương tự như một trong những câu trả lời của con trăn. Ung dung:

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

Chạy như

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

1
Công việc tốt đẹp. Bạn có thể thoát khỏi các dấu ngoặc trong xung quanh mệnh đề if. f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT

Tôi hơi bối rối tại sao phiên bản của bạn không có tiếng vang của bạn return. returntrong R không giống như trong các ngôn ngữ khác, nó thực hiện hủy bỏ sớm. Không sử dụng returnlà thành ngữ. Mặt khác, phiên bản không có người chơi của bạn vẫn có golf if.
Konrad Rudolph

@KonradRudolph Chơi golf iflà sự lười biếng, nhưng returnchỉ là để dễ đọc - nó cho kết quả tương tự dù có hay không return.
BLT

@BLT Hừm. Tôi cảm thấy mạnh mẽ rằng sự vô cớ trong R return làm giảm khả năng đọc vì nó báo hiệu điều sai (thoát sớm) và là một ví dụ của lập trình sùng bái hàng hóa .
Konrad Rudolph

Thật tuyệt, tôi đã học được điều gì đó mới một lần nữa. Đó là một lý do tôi tiếp tục quay trở lại. Cảm ơn @KonradRudolph, câu hỏi về Stack Overflow này cũng rất thú vị: stackoverflow.com/questions/11738823/
BLT

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.