แก้ไข:ในขณะที่บางคนสงสัยว่ามีข้อผิดพลาดในล่ามอย่างเป็นทางการ: ลำดับขององค์ประกอบใน.
ถูกกลับรายการ ฉันมีล่ามสองรุ่นและใช้ผิดที่นี่ ตัวอย่างถูกเขียนขึ้นสำหรับรุ่นที่ไม่ถูกต้อง ฉันแก้ไขล่ามในที่เก็บและตัวอย่างด้านล่าง คำอธิบายของ>
มันค่อนข้างคลุมเครือดังนั้นฉันจึงแก้ไขได้ นอกจากนี้ขอโทษสำหรับการใช้เวลานานมากฉันถูกจับในบางสิ่งในชีวิตจริง
แก้ไข 2:ล่ามของฉันมีข้อบกพร่องในการใช้งาน.
ซึ่งสะท้อนให้เห็นในตัวอย่าง (พวกเขาอาศัยพฤติกรรมที่ไม่ได้กำหนด) ปัญหาได้รับการแก้ไขแล้ว
บทนำ
Shiftเป็นภาษาโปรแกรมฟังก์ชั่นลึกลับที่ฉันสร้างเมื่อสองสามปีก่อน แต่เผยแพร่ในวันนี้ มันเป็นแบบกองซ้อน แต่ก็มีการแกงอัตโนมัติเช่น Haskell
สเปค
มีสองประเภทข้อมูลใน Shift:
- ฟังก์ชั่นซึ่งมีarityบวกโดยพลการ(จำนวนอินพุต) และส่งคืนรายการเอาต์พุต ตัวอย่างเช่นฟังก์ชั่นที่ซ้ำกันของอินพุตเพียงอย่างเดียวมี arity 1 และฟังก์ชั่นที่แลกเปลี่ยนสองอินพุตมี arity 2
- ช่องว่างซึ่งเหมือนกันหมดและไม่มีวัตถุประสงค์อื่นนอกเหนือจากการไม่ทำหน้าที่
โปรแกรม Shift ประกอบด้วยคำสั่งเป็นศูนย์หรือมากกว่าซึ่งแต่ละคำสั่งเป็นอักขระ ASCII เดียว มีทั้งหมด 8 คำสั่ง:
!
( ใช้ ) ปรากฏฟังก์ชั่นf
และคุ้มค่าx
จากสแต็คและนำไปใช้ในการf
x
หากf
มี arity 1 รายการf(x)
จะถูกเพิ่มที่ด้านหน้าของสแต็ก ถ้ามันมี arity ฟังก์ชัน -aryn > 1
ใหม่จะถูกส่งไปยังสแต็ก มันต้องใช้ปัจจัยการผลิตและผลตอบแทน(n-1)
g
x1,x2,...,xn-1
f(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) กับรายการที่ไม่ได้ใช้จากการส่งออกของที่เหลืออยู่ในผลมาจากการf
h
ตัวอย่างเช่นสมมติว่า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
ถ้ามันเป็นฟังก์ชั่น
โปรดทราบว่าคำสั่งทั้งหมดยกเว้นเพียงแค่ผลักดันมูลค่าให้กับกองมีวิธีการดำเนินการป้อนข้อมูลไม่และวิธีเดียวที่จะส่งออกอะไรคือการใช้งาน!
@
โปรแกรมจะถูกตีความโดยการประเมินคำสั่งทีละคนการพิมพ์0
s หรือ1
s เมื่อใดก็ตามที่ "พูด" เรียกว่าและออก พฤติกรรมใด ๆ ที่ไม่ได้อธิบายไว้ที่นี่ (การใช้ช่องว่างการใช้สแต็คความยาว 0 หรือ 1 การเรียก "chain" บนช่องว่าง ฯลฯ ) ไม่ได้กำหนดไว้: ล่ามอาจล้มเหลวล้มเหลวอย่างเงียบ ๆ ขอข้อมูลหรืออะไรก็ตาม
งาน
งานของคุณคือการเขียนล่ามสำหรับ Shift ควรใช้จาก STDIN บรรทัดคำสั่งหรือฟังก์ชันอาร์กิวเมนต์ที่โปรแกรม Shift ถูกตีความและพิมพ์ไปที่ STDOUT หรือส่งกลับผลลัพธ์ (อาจเป็นอนันต์) ของ0
s และ1
s หากคุณเขียนฟังก์ชั่นคุณจะต้องสามารถเข้าถึงเอาต์พุตที่มีความยาวไม่สิ้นสุดในบางวิธี (ตัวสร้างใน Python รายการสันหลังยาวใน Haskell ฯลฯ ) หรือคุณสามารถใช้การป้อนข้อมูลอีกจำนวนn
และการกลับมาอย่างน้อยตัวละครของการส่งออกถ้ามันมีความยาวมากกว่าn
n
จำนวนไบต์ต่ำสุดที่ชนะและช่องโหว่มาตรฐานไม่ได้รับอนุญาต
กรณีทดสอบ
โปรแกรม 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...
โดยจำนวน1
s เพิ่มขึ้นหนึ่งครั้งเสมอ:
@?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!!
ที่เก็บมีเวอร์ชันที่มีคำอธิบายประกอบ
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
เวลาโดยใช้!
และผลลัพธ์ของสิ่งนั้นจะถูกเพิ่มเข้ากับสแต็กหลัก