แก้ไข:ในขณะที่บางคนสงสัยว่ามีข้อผิดพลาดในล่ามอย่างเป็นทางการ: ลำดับขององค์ประกอบใน.ถูกกลับรายการ ฉันมีล่ามสองรุ่นและใช้ผิดที่นี่ ตัวอย่างถูกเขียนขึ้นสำหรับรุ่นที่ไม่ถูกต้อง ฉันแก้ไขล่ามในที่เก็บและตัวอย่างด้านล่าง คำอธิบายของ>มันค่อนข้างคลุมเครือดังนั้นฉันจึงแก้ไขได้ นอกจากนี้ขอโทษสำหรับการใช้เวลานานมากฉันถูกจับในบางสิ่งในชีวิตจริง
แก้ไข 2:ล่ามของฉันมีข้อบกพร่องในการใช้งาน.ซึ่งสะท้อนให้เห็นในตัวอย่าง (พวกเขาอาศัยพฤติกรรมที่ไม่ได้กำหนด) ปัญหาได้รับการแก้ไขแล้ว
บทนำ
Shiftเป็นภาษาโปรแกรมฟังก์ชั่นลึกลับที่ฉันสร้างเมื่อสองสามปีก่อน แต่เผยแพร่ในวันนี้ มันเป็นแบบกองซ้อน แต่ก็มีการแกงอัตโนมัติเช่น Haskell
สเปค
มีสองประเภทข้อมูลใน Shift:
- ฟังก์ชั่นซึ่งมีarityบวกโดยพลการ(จำนวนอินพุต) และส่งคืนรายการเอาต์พุต ตัวอย่างเช่นฟังก์ชั่นที่ซ้ำกันของอินพุตเพียงอย่างเดียวมี arity 1 และฟังก์ชั่นที่แลกเปลี่ยนสองอินพุตมี arity 2
- ช่องว่างซึ่งเหมือนกันหมดและไม่มีวัตถุประสงค์อื่นนอกเหนือจากการไม่ทำหน้าที่
โปรแกรม Shift ประกอบด้วยคำสั่งเป็นศูนย์หรือมากกว่าซึ่งแต่ละคำสั่งเป็นอักขระ ASCII เดียว มีทั้งหมด 8 คำสั่ง:
!( ใช้ ) ปรากฏฟังก์ชั่นfและคุ้มค่าxจากสแต็คและนำไปใช้ในการfxหากfมี arity 1 รายการf(x)จะถูกเพิ่มที่ด้านหน้าของสแต็ก ถ้ามันมี arity ฟังก์ชัน -aryn > 1ใหม่จะถูกส่งไปยังสแต็ก มันต้องใช้ปัจจัยการผลิตและผลตอบแทน(n-1)gx1,x2,...,xn-1f(x,x1,x2,...,xn-1)?( ว่าง ) ผลักว่างไปยังสแต็ก+( โคลน ) เพื่อผลักดันให้สแต็คฟังก์ชั่นเอกที่ซ้ำอินพุต: ค่าใด ๆถูกแมปไปx[x,x]>( shift ) ส่งไปยังสแต็กฟังก์ชัน unary ที่เกิดขึ้นในnฟังก์ชัน -aryfและส่งกลับ(n+1)ฟังก์ชัน -arygที่ละเว้นอาร์กิวเมนต์แรกxเรียกใช้ฟังก์ชันที่fเหลืออยู่และ tacks ที่xด้านหน้าของผลลัพธ์ ยกตัวอย่างเช่นshift(clone)เป็นฟังก์ชั่นไบนารีที่ใช้ปัจจัยการผลิตและผลตอบแทนa,b[a,b,b]/( fork ) ส่งไปยังสแต็กของฟังก์ชันประกอบไปด้วยที่รับสามอินพุตa,b,cและส่งคืน[b]ถ้าaว่างเปล่าและ[c]อื่น ๆ$( เรียก ) ผลักไปที่กองซ้อนฟังก์ชั่นไบนารีที่ปรากฏฟังก์ชั่นfและค่าxและนำfไปใช้กับxเช่นเดียวกับที่!ทำ.( เชน ) ผลักไปที่สแต็กฟังก์ชันเลขฐานสองที่ปรากฏสองฟังก์ชันfและgและคืนค่าการจัดองค์ประกอบ: ฟังก์ชั่นhที่มี arity เดียวกับfและที่รับอินพุตตามปกติจะใช้fกับพวกเขาแล้วนำไปใช้กับผลลัพธ์อย่างเต็มที่gมันหลาย ๆ ครั้งตามคำสั่งของ arity) กับรายการที่ไม่ได้ใช้จากการส่งออกของที่เหลืออยู่ในผลมาจากการfhตัวอย่างเช่นสมมติว่าfเป็นหน้าที่ไบนารีที่โคลนอาร์กิวเมนต์ที่สองของตนและgเป็นโทร หากสแต็คมี[f,g,a,b,c]และเราทำ.!!แล้วมันมี[chain(f,g),a,b,c]; ถ้าเราทำ!!ต่อไปก็fจะถูกนำไปใช้กับa,bการผลิตครั้งแรก[a,b,b]แล้วgถูกนำไปใช้สององค์ประกอบแรกของว่าตั้งแต่ arity ของมันคือ 2, การผลิตและสแต็คในที่สุดก็จะเป็น[a(b),b][a(b),b,c]@( พูด ) ผลักดันฟังก์ชั่นยูนารีเพียงแค่คืนค่าอินพุตและพิมพ์0ถ้ามันว่างเปล่าและ1ถ้ามันเป็นฟังก์ชั่น
โปรดทราบว่าคำสั่งทั้งหมดยกเว้นเพียงแค่ผลักดันมูลค่าให้กับกองมีวิธีการดำเนินการป้อนข้อมูลไม่และวิธีเดียวที่จะส่งออกอะไรคือการใช้งาน! @โปรแกรมจะถูกตีความโดยการประเมินคำสั่งทีละคนการพิมพ์0s หรือ1s เมื่อใดก็ตามที่ "พูด" เรียกว่าและออก พฤติกรรมใด ๆ ที่ไม่ได้อธิบายไว้ที่นี่ (การใช้ช่องว่างการใช้สแต็คความยาว 0 หรือ 1 การเรียก "chain" บนช่องว่าง ฯลฯ ) ไม่ได้กำหนดไว้: ล่ามอาจล้มเหลวล้มเหลวอย่างเงียบ ๆ ขอข้อมูลหรืออะไรก็ตาม
งาน
งานของคุณคือการเขียนล่ามสำหรับ Shift ควรใช้จาก STDIN บรรทัดคำสั่งหรือฟังก์ชันอาร์กิวเมนต์ที่โปรแกรม Shift ถูกตีความและพิมพ์ไปที่ STDOUT หรือส่งกลับผลลัพธ์ (อาจเป็นอนันต์) ของ0s และ1s หากคุณเขียนฟังก์ชั่นคุณจะต้องสามารถเข้าถึงเอาต์พุตที่มีความยาวไม่สิ้นสุดในบางวิธี (ตัวสร้างใน Python รายการสันหลังยาวใน Haskell ฯลฯ ) หรือคุณสามารถใช้การป้อนข้อมูลอีกจำนวนnและการกลับมาอย่างน้อยตัวละครของการส่งออกถ้ามันมีความยาวมากกว่าnn
จำนวนไบต์ต่ำสุดที่ชนะและช่องโหว่มาตรฐานไม่ได้รับอนุญาต
กรณีทดสอบ
โปรแกรม Shift นี้จัดพิมพ์01:
?@!@@!
เริ่มต้นจากทางซ้าย: ผลักที่ว่างเปล่าแล้วกดพูดแล้วใช้คำพูดนั้นกับที่ว่าง ผลลัพธ์0นี้ จากนั้นกดพูดสองครั้งและใช้คำพูดที่สองกับคำแรก ผลลัพธ์1นี้
โปรแกรมนี้วนซ้ำตลอดไปโดยไม่มีผลลัพธ์:
$+.!!+!!
กดcallและcloneจากนั้นใช้chainกับพวกมัน (เราต้องการสอง!s เนื่องจากchainเป็นฟังก์ชันไบนารี) ตอนนี้สแต็กมีฟังก์ชั่นที่รับหนึ่งอาร์กิวเมนต์ทำซ้ำมันและเรียกสำเนาแรกในวินาที ด้วย+!!เราทำซ้ำฟังก์ชั่นนี้และเรียกมันด้วยตัวเอง
โปรแกรมนี้พิมพ์0010:
?@$.++>!.!!.!!.!!!!+?/!!!@!@>!!!
ผลักดันว่างเปล่าและบอกว่า จากนั้นเขียนฟังก์ชั่นไบนารีที่สำเนาอาร์กิวเมนต์ที่สองbแล้วเล่มแรกaและประกอบด้วยมันด้วยตัวเองแล้วใช้องค์ประกอบในการสำเนาของกลับb [a(a(b)),b]ใช้เพื่อพูดและว่างเปล่าจากนั้นใช้พูดกับองค์ประกอบสองอย่างที่เหลืออยู่ในสแต็ก
0โปรแกรมนี้จะพิมพ์ สำหรับแต่ละที่คุณผนวกกับมันพิมพ์เพิ่มเติม!!!0
?@+$>!>!+>!///!!>!>!.!!.!!.!!+!!!!
ผลักดันว่างเปล่าและบอกว่า จากนั้นเขียนฟังก์ชั่นไตรภาคที่จะเป็นปัจจัยการผลิตและผลตอบแทนf,g,x [f,f,g,g(x)]โคลนฟังก์ชันนั้นและนำไปใช้กับตัวเองพูดและช่องว่าง แอปพลิเคชันนี้ไม่เปลี่ยนสแต็กดังนั้นเราจึงสามารถใช้ฟังก์ชั่นอีกครั้งได้หลายครั้งตามที่เราต้องการ
โปรแกรมนี้พิมพ์ลำดับอนันต์001011011101111...โดยจำนวน1s เพิ่มขึ้นหนึ่งครั้งเสมอ:
@?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!!
ที่เก็บมีเวอร์ชันที่มีคำอธิบายประกอบ
f(x1, x2, ..., xn) g(y1, y2, ..., ym)โทรปรากฏทั้งสองของพวกเขาและผลักดันให้ฟังก์ชั่น. ตอนนี้คุณสามารถกินได้ทุกข้อโต้แย้งเหล่านั้นโดยค่อยๆดีความชอบด้วยh(z1, z2, ..., zn) !หลังจากnแอปพลิเคชั่นดังกล่าวฟังก์ชั่นที่เหลือมีเพียงหนึ่งอาร์กิวเมนต์เท่านั้นและ ณ จุดนั้นจะคำนวณf(z1, z2, ..., zn)(เช่นfนำไปใช้กับอาร์กิวเมนต์ทั้งหมดที่คุณ curried) ซึ่งจะผลักดันค่าใหม่บางค่าจากนั้นจะใช้mค่าจากสแต็gก
.ทำงานตรงตามที่ Martin อธิบายยกเว้นว่าหากfส่งคืนรายการที่น้อยกว่าmค่าผลลัพธ์จะไม่ได้กำหนดไว้ (การจัดองค์ประกอบมี arity nดังนั้นจึงไม่สามารถกินอาร์กิวเมนต์เพิ่มเติมจากสแต็กได้) โดยพื้นฐานแล้วเอาต์พุตของfถูกใช้เป็นสแต็กชั่วคราวซึ่งgจะถูกผลักและใช้mเวลาโดยใช้!และผลลัพธ์ของสิ่งนั้นจะถูกเพิ่มเข้ากับสแต็กหลัก