การแกงตามความยาวโดยพลการ


53

เขียนฟังก์ชันfที่ใช้จำนวนเต็มบวกและส่งคืนฟังก์ชัน

fฟังก์ชั่นใหม่กลับควรจะเหมือนกับ อย่างไรก็ตามเมื่อ "การยกเลิกการโทร" เกิดขึ้นfควรส่งคืนผลรวมของจำนวนเต็มทั้งหมดที่ส่งผ่านแทน

ตัวอย่างเช่นg=f(4)(ถ้าfเป็นฟังก์ชันแรก) ควรตั้งgเป็นฟังก์ชั่นอื่น h=g(3)จะทำเช่นเดียวกัน อย่างไรก็ตามเมื่อคุณโทรhโดยไม่มีอาร์กิวเมนต์ (ดูรายละเอียดด้านล่าง) มันควรจะส่งออก 7 เนื่องจากเป็นผลรวมของอาร์กิวเมนต์ของฟังก์ชันก่อนหน้า ใส่อีกวิธีหนึ่ง, f(3)(4)() == 7.

f(3,4)()ไม่ทราบเรื่องนี้ไม่ได้เช่นเดียวกับ

"การยุติการโทร" เป็นหนึ่งในตัวเลือกต่อไปนี้ (ตัวเลือกของคุณ):

  • เรียกอาร์กิวเมนต์ w / o
  • null เป็นอาร์กิวเมนต์
  • ค่าที่ไม่เป็นบวกใด ๆ

จำนวนการเรียกใช้ฟังก์ชันตามอำเภอใจควรได้รับการสนับสนุนไม่มีข้อ จำกัด ที่กำหนดไว้ล่วงหน้า

รับประกันได้ว่ายอดรวมจะไม่มากกว่า 1'000

เราสามารถสันนิษฐานได้ว่ามีการโทรอย่างน้อยหนึ่งครั้งก่อนที่จะ "ยกเลิกการโทร"

รหัสของคุณไม่ควรใช้ตัวแปรแบบคงที่ต่อโปรแกรมดังนั้นจึงควรเป็นไปได้ที่จะเรียกใช้การทดสอบหลายครั้งในรันไทม์เดียวกันและสังเกตพฤติกรรมที่เหมือนกันทุกประการ

ตัวอย่าง:

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

4
@LuisMendo โดยทั่วไปหมายความว่าf(4)จะส่งคืนฟังก์ชันใหม่ ถ้าฟังก์ชั่นใหม่นั้นถูกเรียกใช้โดยไม่มีข้อโต้แย้งมันจะส่งกลับ4แต่ถ้ามันถูกเรียกด้วยอาร์กิวเมนต์อื่นแล้วมันจะส่งกลับฟังก์ชันใหม่ด้วยความหมายเดียวกันอีกครั้งแต่ด้วยอาร์กิวเมนต์ใหม่ที่เพิ่มเข้ามา4และอื่น ๆ
Martin Ender

6
@ LuisMendo มันขึ้นอยู่กับยูจีนจริง ๆ แต่ฉันคิดว่าการอนุญาตให้โทรซ้ำหลายครั้งอาจทำให้ความท้าทายหายไปได้เพราะส่วนที่น่าสนใจไม่ได้เป็นการทำหน้าที่ที่รัฐ
Martin Ender

6
@ มาร์ตินเอนเดอร์มันสมเหตุสมผลมาก ยูจีนถ้านั่นคือเจตนาโปรดเปลี่ยนถ้อยคำของความท้าทาย เขียนฟังก์ชั่นที่สามารถเรียกได้แบบไร้ขีด จำกัดไม่แนะนำเลยว่าฟังก์ชั่น shoud ส่งคืนฟังก์ชัน
Luis Mendo

4
เราสามารถสมมติได้หรือไม่ว่าจะมีเพียงหนึ่งอินสแตนซ์ของเครือข่ายการโทรในแต่ละครั้ง? เช่นq = f(2)(3); b = f(1)(2)(3); q(); b()ไม่
Conor O'Brien

3
เมื่อเร็ว ๆ นี้ฉันได้รับ Haskell ฉันสนใจว่านี่เป็นไปได้หรือไม่ใน Haskell ระบบประเภทที่แข็งแกร่งทำให้ฉันคิดว่ามันอาจจะไม่ใช่
CAD97

คำตอบ:


49

JavaScript (ES6), 18 ไบต์

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

ผ่านค่าที่เป็นเท็จเพื่อดึงผลรวม ศูนย์สามารถได้รับอนุญาตสำหรับค่าใช้จ่าย 2 ไบต์

ลองออนไลน์

Ungolfed:

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

การส่งที่ยอดเยี่ยม!
Eugene D. Gubenkov

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.).(+)

สิ่งนี้นิยาม "function" fซึ่งสามารถเรียกได้ด้วยจำนวนเลขจำนวนเต็มตามด้วยหน่วย()หลังจากนั้นจะส่งคืนจำนวนเต็ม จำเป็นต้องมีคำอธิบายประกอบประเภท ลองออนไลน์!

คำอธิบาย

การบังคับให้ระบบประเภทที่เข้มงวดของ Haskell อนุญาตให้ใช้สิ่งนี้ต้องใช้เวทย์มนตร์บางอย่างกล่าวคือการเปิดใช้งานส่วนขยาย GHC สำหรับอินสแตนซ์ของประเภทงานพิมพ์ที่ยืดหยุ่น วิธีการทำงานนี้คือการที่fเป็นฟังก์ชัน polymorphic parametrically จำกัด โดยข้อ จำกัด ประเภทชั้น: F a => Int -> aชนิดของมันคือ ซึ่งหมายความว่าfจะใช้เวลาเป็นจำนวนเต็มและส่งกลับค่าของชนิดaสำหรับประเภทใด ๆaที่เป็นของ Ftypeclass Fเป็นเพียงชื่อของ typeclass ที่มีฟังก์ชั่นf; มันประกาศในบรรทัดแรก

สองบรรทัดต่อไปมีสองกรณีของประเภทที่แตกต่างกันF aบรรทัดที่สองระบุว่าประเภทของฟังก์ชั่นจาก()ถึงจำนวนเต็มF(ซึ่ง()เป็นประเภทหน่วยที่มีสมาชิกเท่านั้นที่เป็นค่า()) และการดำเนินการคือf n () = n; ฟังก์ชันส่งคืนอาร์กิวเมนต์แรก บรรทัดสุดท้ายระบุว่าหากaเป็นFแล้วจึงไม่ชนิดของฟังก์ชั่นจากจำนวนเต็มไปa: จากฟังก์ชั่นที่เราสามารถสร้างฟังก์ชั่นอื่นf :: Int -> a f :: Int -> Int -> aการใช้งานคือf m n = f (m+n)(รหัสใช้ combinators เพื่อทำให้สั้นลง) โดยที่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 นั้นจะถูก curried โดยอัตโนมัติดังนั้นหากคุณให้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 BTW ในการ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) สิ่งนี้ต้องใช้การส่งคืนฟังก์ชันที่ส่งคืนแต่ละฟังก์ชั่นเป็นฟังก์ชัน

ไวยากรณ์ "currying" นี้ดูค่อนข้างแปลก แต่ก็ค่อนข้างคล้ายกัน ที่จะเลียนแบบหนึ่งจะต้องมีการเขียน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หลังจากการเรียกใช้แต่ละครั้งฟังก์ชันจะไม่สามารถใช้งานได้อีกต่อไป
Conor O'Brien

บางทีฟังก์ชันพอยน์เตอร์? คุณจำเป็นต้องอ้างอิงทุกครั้ง แต่อาจคุ้มค่าที่จะเช็คเอาท์
Downgoat

1
@ ConorO'Brien ฉันเพิ่งใช้แนวทางสหภาพของคุณ มันยาวกว่าอันนี้ แต่มันอยู่ไม่ไกล
Jakob

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][]ใช้กฎนี้จนกว่าเราจะเหลือ
  • ความหมายที่สอง unpacks sumกรณีสุดท้ายนี้ด้วยการกำหนดสิ่งทั้งหมดที่จะประเมินผลการ

1
<การเขียนโปรแกรมเชิงสัญลักษณ์ 3
Julian Wolf

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
}

คำอธิบาย:

หลังจาก preprocessing และฟอร์แมตใหม่ดูเหมือนว่า:

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};ทำสิ่งเดียวกันเมื่อ unary +ไม่เปลี่ยนค่าและอนุญาตให้ใช้เครื่องหมายวงเล็บซ้ำรอบ ๆ ค่าส่งคืน int mและint(m)ทำสิ่งเดียวกันเพราะอนุญาตให้ใส่วงเล็บซ้ำซ้อนรอบชื่อตัวแปรรวมถึงพารามิเตอร์ฟังก์ชัน return {m+a};และreturn {int(m)+a};ทำในสิ่งเดียวกันเมื่อผู้ใช้mจากเป็นintถึงintไม่เปลี่ยนค่าของมัน การเปลี่ยนแปลงเหล่านี้ทำให้การoperator()โอเวอร์โหลดทั้งสองเข้าใกล้กันมากขึ้นในไวยากรณ์ทำให้สามารถเรียกใช้นิยามแมโครเดียวได้สองครั้ง การเลือกลำดับที่ถูกต้องสำหรับสมาชิกทั้งสามคนทำให้คำแรกของบรรทัดถัดไป ( int) รวมอยู่ในคำจำกัดความของแมโครเช่นกัน


1
สวย. และไม่ใช่แค่สารละลายกอล์ฟ ... การบรรทุกเกินพิกัดoperator()เพื่อทำให้งานนี้ยอดเยี่ยมโดยเฉพาะ
Ray Toal


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

ลองออนไลน์!


ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
Dennis

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)

หากเราได้รับอนุญาตให้ระบุการโทรเริ่มต้นf(x)=i(x,0)\nสามารถลดลง12 ไบต์ ( ) และสามารถเรียกได้ด้วยi(number_one,0)(number_two)(...)(negative_number)

ลองมัน!

explination

LaTeX!

ดังแสดงใน LaTex ด้านบนf(x)เพียงแค่เรียกi(x,0)จากนั้นi(x,y)ส่งกลับค่าของyถ้า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 เป็นสิ่งที่จะไม่ขยายในแบบที่คุณต้องการ) นอกจากนั้นไม่มีภาษารุ่นใดที่รองรับทั้งอาร์กิวเมนต์แมโครที่ว่างเปล่าและ impl implant int ดังนั้นโปรแกรม C ที่ถูกต้องไม่สามารถใช้ทั้งสองได้ :) ยังเป็นคำตอบที่ดี คุณกำลังมองหาการเล่นกอล์ฟเพิ่มเติมหรือไม่
hvd

@hvd: ใช่อาจจะกลับมาในอีกสองสามวันและดูว่าฉันสามารถลงสนามได้ไหม คุณถูกต้องแน่นอนว่านี่เป็นพฤติกรรมที่ไม่ระบุ แต่ฉันคิดว่าการรักษามาตรฐานในที่นี้คือภาษานั้นถูกกำหนดโดยการใช้งานของพวกเขาดังนั้นตราบใดที่มันทำงานกับ gcc ฉันมีความสุข
Julian Wolf

ฉันแค่พูดถึงความคิดเห็นที่คุณรวมไว้ในคำตอบของคุณว่าไม่ต้องพึ่งพาส่วนขยายภาษาใด ๆ ใช่แม้จะมีส่วนขยายภาษา แต่ก็ใช้ได้อย่างสมบูรณ์เป็นคำตอบที่นี่ไม่ได้หมายความว่าจะแนะนำอย่างอื่น
hvd

อานั่นยุติธรรมอย่างแน่นอน คุณพูดถูกฉันควรกำหนดว่าในขณะที่ไม่จำเป็นต้องมีการตั้งค่าสถานะพิเศษสิ่งนี้อาจไม่สามารถพกพาได้
Julian Wolf

คุณสามารถทดสอบสำหรับสตริงที่ว่างเปล่ากับแทน*s strlen(s)ซีสตริงนัยยาวยกเลิกโดยมีค่าchar 0แฮ็คมาโครที่ดีเพื่อให้สามารถโทรออกโดยมี / ไม่มีอาร์ค!
Peter Cordes

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) ตำแหน่งของฟังก์ชันสามารถเปลี่ยนแปลงได้โดยไม่ต้องเสียค่าใช้จ่ายเพิ่มเติมเป็นไบต์ วางไว้ที่ offset 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

หลังจากเรียกนี้กับที่ไม่ใช่ศูนย์ขวาน, และบัฟเฟอร์ที่เต็มไปด้วยสำเนาแก้ไขรหัสเครื่องจากbx = sp function16- บิตทันทีในคำสั่งแรกเก็บทั้งหมด (มันเขียนโดยคำสั่งสุดท้ายก่อนหน้าret)

push di/ pop bxอาจถูกแทนที่ด้วยmov bx, di(ก่อนrep movsb) ทำให้มันง่ายขึ้น แต่ไม่มีการออม

กำหนดให้โทรไปผ่านตัวชี้ไปยังบัฟเฟอร์ dst ในdiจะประหยัด 4 spไบต์เทียบกับการคำนวณมันเทียบกับ

การทำให้ที่อยู่เริ่มต้นของฟังก์ชันเหมือนกับขนาดของฟังก์ชันที่จะบันทึกไบต์ ( mov cx, si)


นี่จะเป็นคำตอบที่ดีกว่าถ้าคุณรวมการแยกส่วนของรหัสเครื่อง ตอบเครื่องรหัสแน่นอนต้องเป็นรุ่น ungolfed เช่นใช้objdump -b binaryแทนhexdump -C
Peter Cordes

อัปเดตด้วยการถอดแยกชิ้นส่วนที่แสดงความคิดเห็น การประหยัดที่เป็นไปได้: ต้องการให้ผู้โทรผ่านตัวชี้ dst ในdi(4 ไบต์) ทำให้ฟังก์ชั่นเริ่มต้นที่อยู่ = ขนาด: แทนmov cx, si mov cx, 0x1b
Peter Cordes

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สามารถใช้เป็นBoolean... ฉันลองด้วยnullแต่มันก็นานขึ้น ฉันต้องการใช้??ซึ่งหมายความว่าถ้า LHS เป็นโมฆะทำ RHS แต่เท่าที่ฉันต้องการหาก LHS ไม่เป็นโมฆะ 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 classf ที่เรียกว่าด้วยตัวสร้างการ int กำหนดคลาสเคสซึ่งจะสร้างเมธอดเท่ากับแฮชโค้ด toString และการคัดลอกและอ็อบเจ็กต์ที่แสดงร่วมที่มีชื่อเดียวกันเพื่อเปิดใช้งานการสร้างอ็อบเจ็กต์โดยไม่มีnewคีย์เวิร์ด

คลาสนี้มีวิธีการใช้งานที่มากเกินไป: หนึ่งใช้จำนวนเต็มอื่นเพื่อเพิ่มและสร้างวัตถุใหม่ด้วยผลรวมที่อัปเดตและอีกหนึ่งไม่มีอาร์กิวเมนต์เพื่อรับผลรวม

ในกาลาวัตถุใด ๆ ด้วยวิธีใช้สามารถเรียกว่าชอบวิธีการที่จะสามารถเขียนเป็นo.apply(x) o(x)สิ่งนี้ถูกใช้ใน libary มาตรฐานสำหรับอาร์เรย์, รายการ, แผนที่และ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
Chris

@Chris คุณพูดถูกต้องไม่จำเป็นต้องมี 5.16 การแก้ไขครั้งแรกของฉันทำได้ (โดยใช้__SUB__) แต่ฉันได้เปลี่ยนแปลงก่อนที่จะส่งและไม่ได้ลบบิตประมาณ 5.16 ฉันจะลบมัน ฉันไม่คิดว่าการลดลงmyจะถูกต้อง
ฮอบส์

(และไม่ฉันไม่ได้นับsayเป็นส่วนหนึ่งของรหัสเป็นเพียงเพื่อวัตถุประสงค์ในการอธิบายเท่านั้น)
hobbs

1
หากคุณลบmyโดยไม่use strict, $nเป็นปริยายตัวแปรทั่วโลก มันเป็นรูปแบบที่ไม่ดีในสคริปต์ Perl ที่เหมาะสม แต่มันค่อนข้างธรรมดาในหนึ่งสมุทรและดูเหมือนว่าจะทำงานที่นี่
Chris

2

Brain-Flakขนาด 6 ไบต์

ที่จริงฉันเพิ่งสังเกตเห็นว่าเนื่องจากToS เป็นรูปแบบการส่งคืนที่ถูกต้องการ popping 0ไม่จำเป็นจริง ๆ ซึ่งช่วยประหยัด 2 ไบต์:

({{}})

ลองออนไลน์!

การส่งดั้งเดิม 8 ไบต์

ใช้0เป็นค่าพิเศษ:

({{}}{})

ลองออนไลน์!

คำอธิบาย

ได้รับการขัดแย้ง1 , 2 , ... , n , 0สแต็คแรกมีลักษณะเช่นนี้

                                                       n

                                                       

                                                       a 2

                                                       a 1

                                                       0

จากนั้นโค้ดจะดำเนินต่อไป pops ทุกตัวiสะสมพวกมันปรากฏขึ้น0จะเพิ่มพวกมันและผลักผลลัพธ์:

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

โซลูชันทางเลือก 8 ไบต์

แทนที่จะ popping 0และเพิ่มเข้าไปในผลรวมเราสามารถสลับสแต็คได้ตั้งแต่อันแรกที่ถูกต้องว่างเปล่า:

({{}}<>)

ลองออนไลน์!

การใช้-rแฟล็ก0จะอยู่ด้านบนสุดของสแต็กดังนั้นเราจึงสามารถเปิดมันก่อน:

({}{{}})

ลองออนไลน์!

{}({{}})

ลองออนไลน์!


โอ้ความดีของฉัน ... เยี่ยมมาก!
Eugene D. Gubenkov

2

C (GCC), 83 ไบต์

C golf ครั้งแรกของฉัน! มีวิธีแก้ปัญหา 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 ฉันไม่เห็นว่ามันพูดว่า "ไม่เป็นบวก"
Zacharý

คุณรู้เคล็ดลับนี้หรือไม่? r←⍎condition⊃'else' 'then'
ngn


ความคิดที่บอกว่า 22 ... > _ <
Zacharý


1

Dyvil , 34 ไบต์

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

การใช้งาน :

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

()สามารถละเว้นการติดตามได้

คำอธิบาย :

กำหนดโอเปอเรเตอร์การตีข่าวที่ใช้สอง int และเพิ่มเข้าไป พารามิเตอร์jมีค่าเริ่มต้น0เพื่อรองรับการโทรโดยไม่มีข้อโต้แย้ง 0ในตัวอย่างข้างต้นไม่ได้เป็นชื่อ แต่ตัวอักษร


1

Julia v0.5 +, 52 ไบต์

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

โทรFมา นี่อาจทำให้สั้นลงได้มากโดยใช้วิธี OO ที่น้อยกว่า แต่ฉันมักจะได้รับโอกาสในการใช้สำนวนนี้

หากสามารถสันนิษฐานได้ว่า "การโทรอย่างน้อยหนึ่งครั้งจะถูกดำเนินการก่อนการยกเลิกการโทร" บรรทัดที่สองสามารถลบออกได้เพื่อบันทึก 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;}

หากโปรแกรมต้องยุติหลังจาก Output แทนที่print$sด้วยdie("$s")+ 2 Bytes

เวอร์ชั่นออนไลน์


1
ผมคิดว่าการทำงานควรกลับ $s(ไม่พิมพ์) ดังนั้นคุณสามารถทำอะไรบางอย่างreturn$i?f:$sในตอนท้าย
Conor O'Brien

@ ConorO'Brien ฉันไม่แน่ใจ แต่ถ้าความคิดของคุณถูกต้องมันสามารถประหยัดได้ 5 ไบต์ขอบคุณ
JörgHülsermann

1
ไม่กี่ไบต์สามารถบันทึกด้วยตัวแปร function f($i){return[$_GET[0]+=$i][$i]?:f;}superglobal:
user63956

@ user63956 เป็นความคิดที่ดีมาก
JörgHülsermann

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

R, 54 52 ไบต์

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

บันทึก 2 ไบต์ด้วย MickyT!

คล้ายกับหนึ่งในคำตอบของหลาม Ungolfed:

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

ทำงานเป็น

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

1
ทำได้ดีมาก คุณสามารถกำจัดวงเล็บปีกกาภายในหากประโยค f=function(x){g=function(y='')'if'(y>'',f(x+y),x);g}
MickyT

ฉันค่อนข้างงุนงงว่าทำไม "รุ่นที่returnคุณไม่ได้" returnใน R ไม่เหมือนกับในภาษาอื่น ๆ มันทำการยกเลิกก่อนกำหนด ไม่ได้ใช้returnเป็นสำนวน ในทางกลับกันเวอร์ชันที่ไม่ได้รับเกียรติของคุณยังมีสนามกอล์ฟifอยู่
Konrad Rudolph

@KonradRudolph แข็งแรงเล่นกอล์ฟifเป็นความเกียจคร้าน แต่returnเป็นเพียงสำหรับการอ่าน - returnจะให้ผลเหมือนกันด้วยหรือไม่
BLT

@BLT อืม ผมรู้สึกอย่างแรงกล้าว่าเปล่าใน R return ลดลงอ่านง่ายเพราะมันส่งสัญญาณสิ่งที่ผิด (ถึงแก่กรรมก่อนวัยอันควร) และเป็นตัวอย่างของการเขียนโปรแกรมสินค้าศาสนา
Konrad Rudolph

เยี่ยมฉันได้เรียนรู้สิ่งใหม่อีกครั้ง นั่นเป็นเหตุผลหนึ่งที่ฉันกลับมา ขอบคุณ @KonradRudolph คำถามกองซ้อนนี้ก็น่าสนใจเช่น: stackoverflow.com/questions/11738823/…
BLT

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.