";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))
निर्विरोध संस्करण: कोडिंगग्राउंड पर इसे आज़माएं।
उद्धृत संस्करण: कोडिंग ग्राउंड पर इसे आज़माएं।
ध्यान दें कि आउटपुट कुछ इस तरह दिखता है
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
क्योंकि कोड घोषणा द्वारा व्याख्या की गई है (प्रत्येक ;
एक घोषणा समाप्त होती है) और प्रत्येक घोषणा के मूल्य और प्रकार को दर्शाता है।
पृष्ठभूमि
SML में फॉर्म की एक क्वीन है <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>
-पार में कोई उद्धरण नहीं है और इस प्रकार कुछ भी बचने की आवश्यकता के साथ उद्धृत किया जा सकता है, ए"
क्वीन के उत्पादन के आवश्यक है str(chr 34)
।
वे निहित पहचानकर्ता पर भी बहुत भरोसा करते हैं it
जिसका उपयोग तब किया जाता है जब किसी घोषणा में कोई स्पष्ट पहचानकर्ता नहीं दिया जाता है।
पहले क्वीन में स्ट्रिंग युक्त str(chr 34);
बांधता it
है "
, fn x=>
एक अनाम फ़ंक्शन शुरू करता है एक तर्क लेता है x
, फिर x^it^x^it
परिणामी स्ट्रिंग को समेटता है और प्रिंट करता है। यह अनाम फ़ंक्शन सीधे प्रोग्राम कोड वाले स्ट्रिंग पर लागू किया जाता है, इसलिए समवर्ती x^it^x^it
पैदावार<code>"<code>"
।
दूसरी क्विन स्ट्रिंग के रूप में सिर्फ प्रोग्राम कोड से शुरू होती है ";str(chr 34)^it;print(it^it)";
जो कि बाध्य है it
। फिर str(chr 34)^it;
स्ट्रिंग की शुरुआत के लिए एक उद्धरण को व्यक्त करता है और फिर से कोई स्पष्ट पहचानकर्ता नहीं दिया जाता है, जिसके परिणामस्वरूप स्ट्रिंग "<code>
बाध्य है it
। अंत में print(it^it)
पैदावार के साथ स्ट्रिंग को समेटता है"<code>"<code>
करता है जो फिर मुद्रित होता है।
व्याख्या
संपादित करें: अब 108-बाइट संस्करण के साथ अद्यतित नहीं है, हालांकि कोई भी इस स्पष्टीकरण को पढ़ने के बाद भी इसे समझ सकता है।
उद्धरण-सुरक्षित quine उपरोक्त दोनों दृष्टिकोणों को जोड़ता है और स्वयं प्रपत्र का है "<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)
, है ना? बिल्कुल नहीं, क्योंकि मैंने आपको यह बताने में उपेक्षा की है कि एसएमएल दृढ़ता से टाइप किया गया है जिसका अर्थ है कि एक सशर्त 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 अनिवार्य निर्माणों का भी समर्थन करता है, इसलिए अभिव्यक्तियों के दुष्प्रभाव हो सकते हैं। संक्षेप में, हम -part के (print(it^it);print)
रूप में लेते हैं then
, इस प्रकार पहले मुद्रण करते हैं और फिर फ़ंक्शन को वापस करते हैं print
जिसमें सही प्रकार होता है।