มีวิธีลดฟังก์ชั่นลูกศรไขมันหรือไม่?


15

จากสิ่งที่ฉันเห็นตลอดเวลาที่นี่ใน PPCG รายการ JavaScript ส่วนใหญ่ที่เกี่ยวข้องกับฟังก์ชั่นลูกศรไขมันมักจะเป็นหนึ่งในสองค่าย:

  1. คนธรรมดาที่มีความสามารถในการทำงานเป็นคำสั่งเดียวและกลับคำตอบตรงออกค้างคาวเช่น x=(a,b)=>a*a+b

  2. คนที่มีความซับซ้อนมากขึ้นซึ่งมักจะมีเครื่องหมายปีกกาเนื่องจากการใช้ลูปและเป็นผลให้ต้องใช้returnคำสั่ง ..p=b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

การยกตัวอย่างข้างต้นจากหมวดที่ 2 ด้วยแนวคิดการจัดฟันแบบหยิกเป็นข้อพิสูจน์ของแนวคิด ... จะมีวิธีในการตีรหัสนี้อีกครั้ง (หรือคล้ายกัน) แบบนี้เพื่อกำจัดการจัดฟันแบบหยิกreturnหรือไม่? ฉันแค่ถามสิ่งนี้เนื่องจากอาจเป็นไปได้ (ไม่ได้บอกว่าจะเกิดขึ้นตลอดเวลา) กำจัด 8 ไบต์จากรหัสของนักกอล์ฟ JS มีเทคนิคใดบ้างที่สามารถใช้ในกรณีนี้ได้หรือไม่? ฉันพยายามเรียกซ้ำ แต่m=bคำแถลงนั้นพิสูจน์แล้วว่าเป็นแมลงชนิดหนึ่งเพราะฉันดูเหมือนจะสั่นคลอนไม่ได้

สำหรับรหัสข้างต้นจะมีวิธีการหนึ่งที่กอล์ฟต่อไปเพื่อที่จะกำจัดreturnคำสั่งโดยไม่คำนึงว่ามันจะเล่นกอล์ฟสั้นลงหรือไม่?

คำตอบ:


18

ใช้การเรียกซ้ำ

ฉันพบว่าการเรียกซ้ำเป็น (เกือบ) สั้นกว่าeval+ forเสมอ วิธีทั่วไปในการแปลงจากสำหรับเป็น eval คือ:

for(a=n;b;c);d
(f=a=>b?f(c):d)(n)

ดังนั้นเรามาดูตัวอย่างของคุณ:

b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

ก่อนอื่นเราสามารถทำให้มันง่ายขึ้นเพื่อ:

for(m=b,a=1;~-m;--m,a*=m*m)a%b;

เราทำอะไรที่นี่ ทีนี้เราก็ย้ายทุกอย่างภายในforแถลงการณ์นี้ช่วยเราลดจำนวนอัฒภาคที่ไม่ดีขึ้นโดยตรง แต่มักจะนำไปสู่การเล่นกอล์ฟ


ลองใส่มันลงไปใน eval และเปรียบเทียบกับเวอร์ชั่นเรียกซ้ำ:

b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}
b=>eval('for(m=b,a=1;~-m;--m,a*=m*m)a%b')
b=>(f=a=>~-m?(--m,f(a*=m*m)):a%b)(1,m=b)

ส่วนแรกของ for for loop ( a=n) เราสามารถเริ่มต้นนั้นโดยส่งผ่านตัวแปรเหล่านั้นเป็นอาร์กิวเมนต์ เงื่อนไขนั้นง่าย ๆ : b?(c,f(a)):dที่ไหนdคือค่าที่ส่งคืน มักจะcเพียงแค่ปรับเปลี่ยนaเพื่อให้สามารถผสานเข้ากับมัน ดังนั้นเราจึงสามารถตีกอล์ฟให้มากขึ้นโดยใช้สิ่งที่ฉันได้กล่าวถึง:

b=>(f=a=>~-m?(--m,f(a*=m*m)):a%b)(1,m=b)
b=>(f=a=>~-m?f(a*=--m*m):a%b)(1,m=b) // --m moved into a*=
b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b) // --m moved to condition

ดังที่กล่าวไว้ตามที่ @Niel ระบุไว้ว่าการทำให้อัลกอริทึมของคุณง่ายขึ้น อัลกอริทึมที่เป็นกอล์ฟในภาษาหนึ่งอาจไม่ได้เป็นกอล์ฟในอีกภาษาหนึ่งดังนั้นอย่าลืมลองใช้อัลกอริทึมที่แตกต่างกันและทำการเปรียบเทียบ


1
คุณพลาดการบันทึกจำนวนมากในการทำให้รหัสต้นฉบับง่ายขึ้น ~-mคือm-1ดังนั้นลูปสามารถเป็นได้for(m=b,a=1;--m;a*=m*m)a%b;และเวอร์ชันแบบเรียกซ้ำสามารถเป็นได้ (ยังไม่ทดลอง)b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b)
Peter Taylor

1
บางครั้งคุณต้องใช้อัลกอริทึมที่แตกต่างกัน แต่ในกรณีนี้สิ่งที่ดีที่สุดที่ฉันทำได้คือความยาวเท่ากับคำตอบของ @ PeterTaylor:b=>b>1&(f=a=>--a<2||b%a&&f(a))(b)
Neil

11

การละเมิด eval

มันง่ายมาก แทน:

f=n=>{for(i=c=0;i<n;i++)c+=n;return c}

ใช้

f=n=>eval("for(i=c=0;i<n;i++)c+=n;c")

Eval ส่งคืนคำสั่งที่ประเมินล่าสุด ในกรณีนี้เนื่องจากคำสั่งที่ประเมินล่าสุดจะเป็นc+=nเราจะถูกทิ้งไว้cอย่างใดบันทึกสองไบต์

f=n=>eval("for(i=c=0;i<n;i++)c+=n")

โดยทั่วไป:

f=n=>eval("code;x")

สั้นกว่านี้โดยไบต์:

f=n=>{code;return x}

ในฐานะที่เป็นโน้ตการใช้หลุมฝังศพเพื่อโทรหา eval เพื่อบันทึกไบต์อาจไม่ทำงานเนื่องจาก:

eval`string`

เทียบเท่ากับ

["string"]

มีประโยชน์สำหรับการทำให้งงงวย! ไม่มากนักสำหรับรหัสกอล์ฟ


2
foo`string`เท่ากับเสมอfoo(["string"])มันเป็นแค่ฟังก์ชั่นมากมายแล้วส่งอาร์เรย์กลับไปยังสตริงที่ต้องการ
Neil

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