การพิชิตโลกที่เก่าแก่


16

ความท้าทายนี้จะตามออกHelka Hombaคำถามของการเขียนโปรแกรมที่เก่าแก่โลก จากคำถามนั้นคำจำกัดความของโปรแกรมที่เก่าแก่คือ:

ลองกำหนดโปรแกรมที่เก่าแก่เป็นโปรแกรมที่ไม่มีข้อผิดพลาดใด ๆ แต่จะเกิดข้อผิดพลาดหากคุณแก้ไขโดยการลบสตริงย่อยที่ต่อเนื่องกันของอักขระ N ตัวใดตัว1 <= N < program lengthหนึ่ง

ตัวอย่างเช่นโปรแกรมสามตัวอักษร Python 2

`8`

เป็นโปรแกรมที่เก่าแก่( ขอบคุณ, Sp )เพราะโปรแกรมทั้งหมดที่เกิดจากการลบสตริงย่อยของความยาว 1 ทำให้เกิดข้อผิดพลาด (ข้อผิดพลาดทางไวยากรณ์ในความเป็นจริง แต่ข้อผิดพลาดประเภทใดจะทำ):

8`
``
`8

และโปรแกรมทั้งหมดที่เป็นผลมาจากการลบสตริงย่อยของความยาว 2 ทำให้เกิดข้อผิดพลาด:

`
`

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

หมายเหตุ:

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

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

คำตอบสั้น ๆ เป็นไบต์สำหรับแต่ละภาษาที่ชนะ


ฉันสมมติว่าภาษาที่ไม่มีข้อผิดพลาดไม่สามารถแข่งขันได้
ATaco

@ ATaco น่าเสียดายใช่ ภาษาอื่น ๆ เช่นเสียงกระเพื่อมมีโครงสร้างไวยากรณ์ในลักษณะที่ทำให้โปรแกรมที่เก่าแก่ที่มีประโยชน์เป็นไปไม่ได้
Shelvacu

RIP จริง / อย่างจริงจัง
ATaco

'คำตอบสั้น ๆ เป็นไบต์สำหรับแต่ละภาษาที่ชนะ' ฉันไม่แน่ใจว่าการวัดระยะสั้นเป็นวิธีที่ดีที่สุดสำหรับโปรแกรมที่เก่าแก่
P. Siehr

@ P.Siehr คุณจะแนะนำอะไรแทน
Shelvacu

คำตอบ:


6

Haskell , 132 ไบต์

q x=if length x==132then putStr x else fail[];main=q$(++)<*>show$"q x=if length x==132then putStr x else fail[];main=q$(++)<*>show$"

ลองออนไลน์!

นี่คือส่วนขยายของควิน

main=putStr$(++)<*>show$"main=putStr$(++)<*>show$"

ซึ่งทำงานโดยเชื่อมสตริงข้อมูลกับรุ่นที่ยกมา (โดยใช้show) ของตัวเองและพิมพ์ผลลัพธ์ อย่างไรก็ตามนี่ไม่ใช่สิ่งที่บริสุทธิ์เนื่องจากอักขระใด ๆ ในสตริงข้อมูลสามารถลบออกได้โดยไม่ล้มเหลวและยังสามารถทิ้งบางส่วน$(++)<*>show$หรือ(++)<*>บางส่วนได้โดยไม่ทำให้โปรแกรมแตก

เพื่อแก้ไขปัญหานี้ฟังก์ชั่นการพิมพ์ที่กำหนดเองqถูกกำหนดไว้ซึ่งการตรวจสอบความยาวของสตริงที่กำหนดและสายfailถ้ามันสั้นกว่า 132 จับนี้เอาของลำดับใด ๆ จากข้อมูลสตริงและยังลบของ$(++)<*>show$หรือ(++)<*>ในขณะที่ทั้งสองกรณีที่เกิดขึ้น สตริงที่ส่งไปยังqสั้นกว่า

ในqจำนวน132อาจจะลงไป1, 13, 32หรือ2แต่ในแต่ละกรณีอีกครั้งfailเรียกว่า

เท่าที่ฉันสามารถบอกได้การลบซับสตริงอื่นทำให้เกิดข้อผิดพลาดทางไวยากรณ์หรือชนิดดังนั้นโปรแกรมไม่ได้คอมไพล์ในตอนแรก (ระบบพิมพ์ที่เข้มงวดของ Haskell มีประโยชน์ในที่นี้)

แก้ไข:ขอบคุณØrjan Johansen และ Shelvacu ที่ชี้ให้เห็นข้อบกพร่อง!


ฉันเกรงว่าfail[]|length x/=122จะถูกลบออก fail[]:[putStr x|length x==122]อาจทำงานได้ดีขึ้น
Ørjan Johansen

ไม่|length x==122สามารถถอดออกได้ if length x==122 then putStr x else fail[]บางที?
Ørjan Johansen

@ ØrjanJohansenจับได้ดีฉันมีif then elseมาก่อน แต่คิดว่าฉันจะย่อให้สั้นลงได้
Laikoni

2
putStr xสามารถกลายเป็นp xซึ่งเมื่อฉันลองในระบบของฉันวิ่งเป็นเวลานานมากก่อนที่ฉันจะฆ่ามันฉันสงสัยว่าการเรียกซ้ำแบบหางเรียกนั้นได้รับการปรับให้เหมาะสมที่สุดดังนั้นจึงเป็นวงวนไม่สิ้นสุด ฉันมีความรู้ไม่เพียงพอที่จะให้คำแนะนำเกี่ยวกับวิธีการแก้ไข
Shelvacu

@Shelvacu อ๊ะ การเปลี่ยนชื่อpเป็นqควรแก้ไข
Ørjan Johansen

4

Python 3 , 113 ไบต์

for[]in{113:[]}[open(1,"w").write((lambda s:s%s)('for[]in{113:[]}[open(1,"w").write((lambda s:s%%s)(%r))]:a'))]:a

ลองออนไลน์!

มันทำงานอย่างไร

เราไม่สามารถใช้คำสั่งหลายรายการได้อย่างง่ายดายเนื่องจากสามารถลบคำสั่งที่สองได้ดังนั้นเราจึงเริ่มด้วย quine นิพจน์เดียว:

print((lambda s:s%s)('print((lambda s:s%%s)(%r))'))

เพื่อป้องกันการลบ substring เราจะใช้แทนopen(1,"w").write printใน Python 3 writeส่งคืนจำนวนอักขระที่เขียนซึ่งเราจะตรวจสอบคือ113ให้แน่ใจว่าไม่มีการลบส่วนใดส่วนหนึ่งของสตริง เราทำสิ่งนี้โดยค้นหาค่าส่งคืนในพจนานุกรม{113:[]}และวนรอบผลลัพธ์ด้วยfor[]in…:aซึ่งจะล้มเหลวหากเราไม่ได้รับ iterable ที่ว่างเปล่าหรือถ้าforคำสั่งนั้นถูกลบ


1
คุณสามารถให้คำอธิบายว่ารหัสของคุณทำงานอย่างไร
Shelvacu

@Shelvacu ใช่เพิ่ม
Anders Kaseorg

3

ทับทิม 78 ไบต์

eval(*[($>.write((s=%{eval(*[($>.write((s=%%{%s})%%s)-78).chr])})%s)-78).chr])

ฉันเขียนสิ่งนี้เมื่อฉันคิดถึงความท้าทายเพื่อให้แน่ใจว่าเป็นไปได้ มันใช้ "wrapper" เดียวกันจากหนึ่งในคำตอบของฉันกับความท้าทายดั้งเดิม

คำอธิบาย:

  • eval(*[ expr ])

    สิ่งนี้จะประเมินว่าโค้ดใดที่ส่งคืนเป็นโปรแกรมทับทิม นี่เป็นการทดสอบว่าสตริงที่โค้ดส่งคืนเป็นโปรแกรมรูบี้ที่ถูกต้องหรือไม่ สะดวกสบายโปรแกรมทับทิมสามารถว่างเปล่าหรือประกอบด้วยช่องว่างเท่านั้น

    โอเปอเรเตอร์ "splat" *อนุญาตให้คุณใช้อาร์เรย์เป็นอาร์กิวเมนต์ของฟังก์ชัน ซึ่งหมายความว่าหากevalลบออกโปรแกรมที่ได้คือ(*[ expr ])ซึ่งไม่ใช่ ruby ​​ที่ถูกต้อง

  • ($>.write( STR )-78).chr

    $> เป็นตัวแปรสั้นสำหรับ STDOUT

    $>.write(foo) เขียน foo ไปยัง STDOUT และที่สำคัญสำหรับรหัสนี้จะคืนค่าจำนวนไบต์ที่เขียน

    $>.write(foo)-78: นี่78คือความยาวของโปรแกรมและดังนั้นหากโปรแกรมไม่ได้ถูกพันกันก็จะเป็นจำนวนไบต์ที่เขียน ดังนั้นในกรณีที่ไม่มีข้อผิดพลาดสิ่งนี้จะคืนค่าศูนย์

    num.chrส่งคืน num เป็นอักขระเช่น0.chrจะส่งคืนสตริงที่มีค่า null หนึ่งไบต์ ในโปรแกรม unmangled สิ่งนี้จะให้สตริงที่มีค่า null หนึ่งไบต์ถึงevalซึ่งเป็นโปรแกรม ruby ​​ที่ถูกต้องซึ่งเป็นแบบไม่มี op

    นอกจากนี้โปรแกรมสามารถลบสตริงย่อยออกได้ซึ่งเป็นเพียงeval(*[(78).chr])หรือeval(*[(8).chr])ซึ่งหมายความว่าค่าคงที่ตัวเลขไม่สามารถลงท้ายด้วยตัวเลขใด ๆ ได้ (0, 4, 9, 10, 11, 12, 13, 26, 32, 35, 35 , 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 64, 95) เพราะมันเป็นรหัส ASCII สำหรับโปรแกรมทับทิมตัวอักษรเดียวที่ถูกต้อง

  • %{ STR }

    นี่เป็นไวยากรณ์ที่รู้จักกันน้อยกว่าสำหรับตัวอักษรสตริงในทับทิม เหตุผลที่ใช้ที่นี่คือคู่ที่สมดุลของ{}สามารถใช้ภายในสตริงซึ่งหมายความว่าไวยากรณ์นี้สามารถมีตัวเอง ยกตัวอย่างเช่นเป็นเช่นเดียวกับ%{foo{bar}}"foo{bar}"

  • (s=%{ ข้อมูล })%s

    นี้กำหนดตัวแปรsซึ่งเป็นข้อมูลของควินนี้เป็นสตริง printf

    การมอบหมายในทับทิมส่งคืนสิ่งที่ได้รับมอบหมายดังนั้นสิ่งนี้จึงเหมือนกับการมอบหมายครั้งแรกsและจากนั้นเรียกใช้s%s

    %บนสตริงคือน้ำตาล syntatic สำหรับ ruby ​​เทียบเท่ากับ sprintf %sหมายที่ภายในข้อมูลข้อมูลที่ตัวเองควรจะฝัง

    รหัสบิตนี้กำหนดส่วนข้อมูลของควินินและฝังไว้ภายในตัวมันเองเพื่อสร้างรหัสเต็ม


3

ML มาตรฐาน (MLton) , 204 182 189 ไบต์

val()=hd[(fn s=>let val$ =s^"\""^String.toString s^"\"]"val(189,%)=(size$,$)in print%end)"val()=hd[(fn s=>let val$ =s^\"\\\"\"^String.toString s^\"\\\")\"val(189,%)=(size$,$)in print%end)"]

ลองออนไลน์!

สำหรับ MLton โปรแกรม SML เต็มรูปแบบจะถูกคั่นด้วยนิพจน์และยกเลิกโดย;(เช่นprint"Hello";print"World";) หรือการประกาศด้วยvarและfunคีย์เวิร์ด (เช่นvar _=print"Hello"var _=print"World") โดยที่_เป็น wild card ซึ่งสามารถแทนที่ด้วยชื่อตัวแปรใด ๆ ก็ได้

ตัวเลือกแรกไม่มีประโยชน์สำหรับการเขียนโปรแกรมที่เก่าแก่เพราะ;ในตัวมันเป็นโปรแกรมที่ถูกต้อง (ซึ่งไม่ทำอะไรเลย แต่ไม่มีข้อผิดพลาดอย่างใดอย่างหนึ่ง) ปัญหาด้วยวิธีที่สองคือการประกาศเช่นvar _=print"Hello"สามารถสั้นลงเพียงvar _="Hello"(หรือแม้กระทั่งvar _=print) เพราะการประกาศด้วยvarผลงานตราบใดที่ด้านขวาเป็นนิพจน์ SML ที่ถูกต้องหรือค่า (SML เป็นภาษาที่ใช้งานได้ดังนั้นฟังก์ชันสามารถ ใช้เป็นค่าเกินไป)

ณ จุดนี้ฉันก็พร้อมที่จะประกาศการเขียนโปรแกรมที่เก่าแก่ใน SML เป็นไปไม่ได้เมื่อฉันบังเอิญพบรูปแบบการจับคู่ในval-declarations ปรากฎว่าไวยากรณ์สำหรับการประกาศไม่ใช่val <variable_name> = <expression>แต่val <pattern> = <expression>ที่รูปแบบอาจประกอบด้วยชื่อตัวแปรค่าคงที่และตัวสร้าง ในฐานะที่เป็นprintฟังก์ชั่นมีประเภทstring -> unitเราสามารถใช้รูปแบบการแข่งขันในunit-value ในการบังคับใช้ที่ฟังก์ชั่นการพิมพ์ถูกนำไปใช้จริงสตริง:() val()=print"Hey"ด้วยวิธีการนี้ให้ลบอย่างใดอย่างหนึ่งprintหรือ"Hey"ผลในPattern and expression disagree-error

ด้วยวิธีการพิมพ์ที่เก่าแก่นี้อยู่ในมือขั้นตอนต่อไปคือการเขียนคำพูดก่อนที่จะต้องมีการเพิ่มการป้องกันแบบประหยัด ก่อนหน้านี้ฉันใช้เทคนิค SML Quine ง่าย ๆ (ดูประวัติการแก้ไข ) แต่ Anders Kaseorg ชี้ให้เห็นถึงวิธีการที่แตกต่างกันซึ่งสามารถบันทึกไบต์ได้ในกรณีของเขา มันใช้String.toStringฟังก์ชั่นในตัวเพื่อจัดการกับการหลบหนีสตริงและเป็นของรูปแบบทั่วไป<code>"<data>"ที่"<data>"เป็นสตริงที่หลบหนีจากcodeก่อนหน้านี้:

val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"

นี่คือควินินที่ใช้งานได้ แต่ยังไม่บริสุทธิ์ ก่อนอื่น Anders Kaseorg พบว่า MLton ยอมรับการเสนอราคาเดียว"เป็นรหัสโดยไม่มีข้อผิดพลาดซึ่งหมายความว่าเราไม่สามารถมีรหัสสิ้นสุดในการอ้างอิงดังกล่าวข้างต้น ทางที่สั้นที่สุดเพื่อป้องกันไม่ให้เรื่องนี้จะเป็นที่จะตัดทุกอย่างหลังจากval()=ในคู่ของวงเล็บ val()=()แต่แล้วรหัสอาจจะลดลงไป วิธีที่สั้นที่สุดที่สองที่ฉันพบคือใช้val()=hd[ ... ]นั่นคือเราห่อทุกอย่างไว้ในรายการและคืนองค์ประกอบแรกเพื่อให้ตัวตรวจสอบชนิดมีความสุข

เพื่อให้แน่ใจว่าไม่มีส่วนใดของสตริงข้อมูลที่สามารถลบออกได้โดยไม่สังเกตเห็นการจับคู่รูปแบบในval-declarations มีประโยชน์อีกครั้ง: ความยาวของสตริงสุดท้ายที่จะพิมพ์ (และความยาวของโปรแกรม) ควรเท่ากับ 195 ดังนั้น เราสามารถเขียนlet val t=... val 195=size t in print t endในร่างกายของสิ่งที่เป็นนามธรรมแทนfn print(...)การลบส่วนหนึ่งของสตริงส่งผลให้มีความยาวน้อยกว่า 189 จึงทำให้เกิดBindข้อยกเว้นขึ้น

ยังมีปัญหาเหลืออยู่: การval 195=size tตรวจสอบทั้งหมดอาจถูกยกเลิกได้ เราสามารถป้องกันสิ่งนี้ได้ด้วยการขยายการตรวจสอบให้ตรงกับสิ่งอันดับ: val t=... val(216,u)=(n+size t,t)in print u endเช่นการลบผลการตรวจสอบในตัวแปรที่ไม่ได้ผูกuไว้

ทั้งหมดนี้ให้โซลูชัน 195 ไบต์ต่อไปนี้:

val()=hd[(fn s=>let val t=s^"\""^String.toString s^"\")"val(195,u)=(size t,t)in print u end)"val()=hd[(fn s=>let val t=s^\"\\\"\"^String.toString s^\"\\\")\"val(195,u)=(size t,t)in print u end)"]

ใช้เคล็ดลับการเล่นกอล์ฟของการใช้ชื่อตัวแปรประกอบการเช่น!, $และ%แทนn, tและuเพื่อประหยัดพื้นที่สีขาวบาง (ดูเคล็ดลับนี้ ) นำไปสู่ขั้นสุดท้ายรุ่น 182 ไบต์

การลบซับสตริงอื่นทั้งหมดที่ไม่ได้ระบุไว้อย่างชัดเจนในคำอธิบายควรส่งผลให้เกิดข้อผิดพลาดทางไวยากรณ์หรือชนิด

แก้ไข 1: เป็นเพียงlength(explode t) แก้ไข 2:ขอบคุณ Anders Kaseorg สำหรับแนวทางแบบควินอื่นและชี้ให้เห็น "ช่องโหว่"size t


by2 ไบต์โดยเขียน"\""โดยตรงและใช้String.toStringเพื่อหลบหนี
Anders Kaseorg

เดี๋ยวก่อนนี่มันน่าสยดสยอง: MLton ดูเหมือนจะยอมรับโปรแกรม"ทำให้เกิดเอาต์พุตว่าง ( TIO )
Anders Kaseorg

@AndersKaseorg Huh แปลกดี let ... in ... endแต่มันควรจะเป็นไปได้ที่จะแก้ไขปัญหานี้โดยใช้อีก
Laikoni

@AndersKaseorg ฉันแก้ไขปัญหานี้โดยหวังว่าจะไม่แนะนำ "ช่องโหว่" ใหม่
Laikoni

ที่จริงฉันดูที่ MLton ยอมรับ"ว่าเป็นโปรแกรมและดูเหมือนว่าข้อผิดพลาดได้รับการแก้ไขในการกระทำนี้ดังนั้นบางที 182 หรือ 180 ของฉันก็ใช้ได้ดีตราบใดที่คุณระบุรุ่น Git ที่ยังไม่เผยแพร่ของ MLton
Anders Kaseorg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.