";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
เวอร์ชันที่ไม่ได้อ้างอิง: ลองใช้บน codingground
รุ่นที่ยกมา: ลองใน codingground
โปรดทราบว่าผลลัพธ์มีลักษณะเช่นนี้
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
เพราะรหัสถูกตีความประกาศโดยการประกาศ (แต่ละ;ปลายประกาศ) และแสดงค่าและประเภทของการประกาศแต่ละ
พื้นหลัง
ใน SML มีรูปแบบ quine <code>"<code in quotes>":
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
และหนึ่งในรูปแบบ"<code in quotes>"<code>:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
ทั้งสองต้องพึ่งพาความจริงที่ว่า<code>-part มีคำพูดใด ๆ ดังนั้นจึงสามารถอ้างที่มีออกมาความจำเป็นในการหลบหนีอะไรที่จำเป็นในการส่งออกควินจะได้รับโดย"str(chr 34)
พวกเขายังต้องพึ่งพาตัวบ่งชี้นัยitซึ่งใช้เมื่อไม่มีตัวระบุที่ชัดเจนในการประกาศ
ในควินแรกstr(chr 34);ผูกitกับสตริงที่มี", fn x=>เริ่มต้นการทำงานที่ไม่ระบุชื่อการหนึ่งโต้แย้งxแล้ว concatenates x^it^x^itและพิมพ์สตริงที่เกิด ฟังก์ชั่นนี้ไม่ระบุชื่อถูกนำมาใช้โดยตรงกับสตริงที่มีรหัสโปรแกรมเพื่อการ concatenation อัตราผลตอบแทนx^it^x^it<code>"<code>"
ที่สองควินเริ่มต้นที่มีเพียงแค่รหัสโปรแกรมเป็นสตริงที่ถูกผูกไว้กับ";str(chr 34)^it;print(it^it)"; itจากนั้นstr(chr 34)^it;เชื่อมใบเสนอราคาจะเริ่มต้นของสตริงและเป็นอีกครั้งระบุไม่ชัดเจนจะได้รับสตริงส่งผลให้ถูกผูกไว้กับ"<code> itในที่สุดprint(it^it)concatenates สตริงด้วยตัวเองยอม"<code>"<code>ซึ่งพิมพ์แล้ว
คำอธิบาย
แก้ไข:ไม่ทันสมัยกับรุ่น 108 ไบต์ แต่อาจเข้าใจได้หลังจากอ่านคำอธิบายนี้แล้ว
"<code>"<code>อ้างปลอดภัยรวมทั้งควินของวิธีการข้างต้นและเป็นตัวเองของแบบฟอร์ม การใส่สิ่งนี้ลงไปอีกครั้งในเครื่องหมายคำพูดทำให้""<code>"<code>"เราได้สตริงที่ว่างแล้วจึงเป็นแบบฟอร์มอื่น
นั่นหมายความว่าโปรแกรมนั้นจะได้รับแหล่งที่มาของตัวเองในรูปแบบ"<code>โดยตัวระบุitหรือitเป็นเพียง"และเราจะได้รับแหล่งที่มาของเรา<code>เป็นข้อโต้แย้งและจะต้องเป็นฟังก์ชั่นที่จัดการข้อโต้แย้งดังกล่าว
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
ในการระบุในกรณีที่เราเป็นเราตรวจสอบว่าขนาดของitมีขนาดใหญ่กว่า 1 ถ้าไม่itเป็น"และเราอยู่ในกรณีที่สองดังนั้นelseส่วนที่ส่งกลับฟังก์ชั่นที่ไม่ระบุชื่อfn x=>print(it^it^x^it^x^it)ซึ่งถูกเรียกเพราะมันตามมาด้วยสตริง . สังเกตส่วนนำit^it^ที่จำเป็นสำหรับสตริงว่างตอนเริ่มต้นของโปรแกรม
หากsize itมีขนาดใหญ่กว่า 1 เราอยู่ในthenส่วนและเพียงดำเนินการprint(it^it)ใช่ไหม? ไม่มากนักเพราะฉันละเลยที่จะบอกคุณว่า SML พิมพ์อย่างรุนแรงซึ่งหมายความว่าเงื่อนไขif <cond> then <exp_1> else <exp_2>ต้องมีประเภทเดียวกันเสมอซึ่งหมายความว่าการแสดงออก<exp_1>และ<exp_2>จำเป็นต้องมีประเภทเดียวกันเสมอ เรารู้อยู่แล้วว่าประเภทของelseส่วน: ฟังก์ชั่นที่ไม่ระบุชื่อซึ่งจะใช้เวลาสตริงแล้วเรียกprintมีประเภทstring -> <return type of print>และprintมีประเภทstring -> unit( unitอยู่ในวิธีการบางอย่างที่คล้ายกับvoidในภาษาอื่น ๆ ) string -> unitดังนั้นชนิดที่เกิดขึ้นอีกครั้ง
ดังนั้นถ้าthenส่วนนั้นเป็นเพียงแค่print(it^it)ที่มีประเภทunitเราจะได้รับข้อผิดพลาดประเภทไม่ตรงกัน แล้วไงfn _=>print(it^it)ล่ะ ( _เป็นตัวแทนสำหรับอาร์กิวเมนต์ที่ไม่ได้ใช้) ฟังก์ชั่นที่ไม่ระบุตัวตนนี้มีประเภท'a -> unitที่'aยืนสำหรับประเภทใด ๆ ดังนั้นในบริบทของเงื่อนไขของเราซึ่งบังคับใช้string -> unitประเภทนี้จะทำงาน (ตัวแปรประเภท'aรับอินสแตนซ์กับประเภทstring) อย่างไรก็ตามในกรณีนี้เราจะไม่พิมพ์อะไรเลยเพราะฟังก์ชั่นที่ไม่ระบุชื่อจะไม่ถูกเรียก! จำไว้ว่าเมื่อเราเข้าไปในthenส่วนของรหัสโดยรวมคือ"<code>"<code>ดังนั้น<code>ส่วนที่ประเมินถึงฟังก์ชั่น แต่เนื่องจากไม่มีอะไรเกิดขึ้นหลังจากนั้นมันไม่ได้ถูกเรียก
แต่เราใช้ sequentialisation ซึ่งมีแบบฟอร์ม(<exp_1>; ...; <exp_n>)ที่<exp_1>จะ<exp_n-1>อาจจะมีประเภทโดยพลการและประเภทของการ<exp_n>ให้บริการประเภทของ sequentialisation ทั้ง จากมุมมองการทำงานค่าของ<exp_1>ถึง<exp_n-1>ถูกยกเลิกอย่างง่าย ๆ อย่างไรก็ตาม SML ยังสนับสนุนโครงสร้างที่จำเป็นเพื่อให้การแสดงออกอาจมีผลข้างเคียง ในระยะสั้นเราทำ(print(it^it);print)หน้าที่เป็นthenส่วนที่ดังนั้นการพิมพ์ครั้งแรกแล้วกลับมาฟังก์ชั่นprintที่มีประเภทที่ถูกต้อง