मैं अभी सोच रहा हूं कि कैसे खुद को समझाऊं कि ट्यूरिंग मशीनें कम्प्यूटेशन का एक सामान्य मॉडल हैं। मैं इस बात से सहमत हूं कि कुछ मानक पाठ्यपुस्तकों, जैसे कि सिपर में चर्च-ट्यूरिंग थीसिस का मानक उपचार बहुत पूरा नहीं है। यहाँ एक स्केच है कि मैं ट्यूरिंग मशीनों से अधिक पहचानने योग्य प्रोग्रामिंग भाषा में कैसे जा सकता हूं।
एक ब्लॉक-संरचना प्रोग्रामिंग के साथ भाषा पर विचार करें if
और while
बयान, साथ गैर पुनरावर्ती नामित के साथ परिभाषित कार्यों और सबरूटीन्स, बूलियन यादृच्छिक चर और सामान्य बूलियन अभिव्यक्ति, और एक भी असीम बूलियन सरणी के साथ tape[n]
एक पूर्णांक सरणी सूचक के साथ n
कि वृद्धि की जा सकती है या कम कर, n++
या n--
। सूचक n
शुरू में शून्य है और सरणी tape
शुरू में सभी शून्य है। तो, यह कंप्यूटर भाषा सी-लाइक या पायथन जैसी हो सकती है, लेकिन यह अपने डेटा प्रकारों में बहुत सीमित है। वास्तव में, वे इतने सीमित हैं कि हमारे पास n
बूलियन अभिव्यक्ति में सूचक का उपयोग करने का एक तरीका भी नहीं है । ऐसा मानते हुएtape
केवल दाईं ओर अनंत है, हम n
कभी भी नकारात्मक होने पर पॉइंटर अंडरफ्लो "सिस्टम एरर" की घोषणा कर सकते हैं । साथ ही, हमारी भाषा में exit
एक तर्क के साथ एक कथन है, बूलियन उत्तर को आउटपुट करने के लिए।
फिर पहला बिंदु यह है कि यह प्रोग्रामिंग भाषा ट्यूरिंग मशीन के लिए एक अच्छी विनिर्देशन भाषा है। आप आसानी से देख सकते हैं कि, टेप ऐरे को छोड़कर, कोड में केवल बहुत से संभावित राज्य हैं: इसके घोषित चर के सभी, और निष्पादन की वर्तमान रेखा, और इसके सबरूटीन स्टैक की स्थिति। उत्तरार्द्ध में केवल एक सीमित मात्रा में राज्य है, क्योंकि पुनरावर्ती कार्यों की अनुमति नहीं है। आप एक "कंपाइलर" की कल्पना कर सकते हैं जो इस प्रकार के कोड से "वास्तविक" ट्यूरिंग मशीन बनाता है, लेकिन उस का विवरण महत्वपूर्ण नहीं है। मुद्दा यह है कि हमारे पास एक प्रोग्रामिंग भाषा है जिसमें बहुत अच्छे वाक्यविन्यास हैं, लेकिन बहुत आदिम डेटा प्रकार हैं।
निर्माण के बाकी हिस्सों को लाइब्रेरी कार्यों और प्री-कंपोजिशन चरणों की सीमित सूची के साथ एक अधिक जीवंत प्रोग्रामिंग भाषा में परिवर्तित करना है। हम निम्नानुसार आगे बढ़ सकते हैं:
एक precompiler के साथ, हम बूलियन डेटा प्रकार को ASCII जैसे बड़े लेकिन परिमित प्रतीक वर्णमाला में विस्तारित कर सकते हैं। हम मान सकते हैं कि tape
इस बड़ी वर्णमाला में मान लिया गया है। हम टेप की शुरुआत में एक मार्कर छोड़ सकते हैं ताकि पॉइंटर अंडरफ़्लो को रोका जा सके, और टेप के अंत में टीएम को स्केटिंग से अनन्तता तक रोकने के लिए टेप के अंत में एक चल मार्कर। हम प्रतीकों if
और while
बयानों के लिए बूलियन के बीच मनमाने ढंग से द्विआधारी संचालन को लागू कर सकते हैं । (वास्तव में if
इसे लागू किया जा सकता है while
, अगर यह उपलब्ध नहीं था।)
ककमैंमैंक
हम एक टेप को प्रतीक-मूल्यवान "मेमोरी" और दूसरे को अहस्ताक्षरित, पूर्णांक-मूल्यवान "रजिस्टरों" या "वैरिएबल" के रूप में नामित करते हैं। हम पूर्णांक बाइनरी को समाप्ति मार्करों के साथ पूर्णांक संग्रहीत करते हैं। हम पहले एक रजिस्टर की कॉपी और एक रजिस्टर के बाइनरी डिक्रीमेंट को लागू करते हैं। मेमोरी पॉइंटर के बढ़ने और घटने के साथ संयोजन करके, हम प्रतीक मेमोरी के यादृच्छिक अभिगम को लागू कर सकते हैं। बाइनरी जोड़ और पूर्णांक के गुणन की गणना करने के लिए हम फ़ंक्शन भी लिख सकते हैं। बिटवाइज़ ऑपरेशंस के साथ बाइनरी एड फंक्शन, और लेफ्ट शिफ्ट के साथ 2 से गुणा करना एक फंक्शन लिखना मुश्किल नहीं है। (या वास्तव में सही बदलाव, चूंकि यह थोड़ा-सा है।) इन आदिमताओं के साथ, हम लंबे गुणा एल्गोरिथ्म का उपयोग करके दो रजिस्टरों को गुणा करने के लिए एक फ़ंक्शन लिख सकते हैं।
हम सूत्र का उपयोग करके एक-आयामी प्रतीक सरणी symbol[n]
से दो-आयामी प्रतीक सरणी में मेमोरी टेप को पुनर्गठित कर सकते हैं । अब हम बाइनरी में एक अहस्ताक्षरित पूर्णांक को समाप्ति चिह्न के साथ व्यक्त करने के लिए एक-आयामी, यादृच्छिक-अभिगम, पूर्णांक-मूल्यवान स्मृति प्राप्त करने के लिए स्मृति की प्रत्येक पंक्ति का उपयोग कर सकते हैं । हम मेमोरी से एक पूर्णांक रजिस्टर में रीडिंग को लागू कर सकते हैं, और एक रजिस्टर से मेमोरी में लिख सकते हैं। कई विशेषताएं अब फ़ंक्शंस के साथ लागू की जा सकती हैं: हस्ताक्षरित और फ़्लोटिंग पॉइंट अंकगणित, प्रतीक तार आदि।symbol[x,y]
n = (x+y)*(x+y) + y
memory[x]
केवल एक और बुनियादी सुविधा को सख्ती से एक प्री-कंपाइलर की आवश्यकता होती है, अर्थात पुनरावर्ती कार्य। यह एक तकनीक के साथ किया जा सकता है जो व्यापक रूप से व्याख्या की गई भाषाओं को लागू करने के लिए उपयोग किया जाता है। हम प्रत्येक उच्च-स्तरीय, पुनरावर्ती फ़ंक्शन को एक नाम स्ट्रिंग प्रदान करते हैं, और हम निम्न-स्तरीय कोड को एक बड़े while
लूप में व्यवस्थित करते हैं जो सामान्य पैरामीटर के साथ कॉल स्टैक बनाए रखता है: कॉलिंग पॉइंट, कॉल फ़ंक्शन और तर्कों की एक सूची।
इस बिंदु पर, निर्माण में एक उच्च-स्तरीय प्रोग्रामिंग भाषा की पर्याप्त विशेषताएं हैं जो आगे की कार्यक्षमता सीएस सिद्धांत के बजाय प्रोग्रामिंग भाषाओं और संकलकों का विषय है। इस विकसित भाषा में ट्यूरिंग-मशीन सिम्युलेटर लिखना भी पहले से आसान है। भाषा के लिए एक आत्म-संकलक लिखना बिल्कुल आसान नहीं है, लेकिन निश्चित रूप से मानक है। बेशक आपको इस सी-सी या पायथन जैसी भाषा में एक कोड से बाहरी टीएम बनाने के लिए बाहरी कंपाइलर की आवश्यकता होती है, लेकिन यह किसी भी कंप्यूटर भाषा में किया जा सकता है।
ध्यान दें कि यह स्केच किया गया कार्यान्वयन न केवल पुनरावर्ती कार्य वर्ग के लिए तर्कवादियों के चर्च-ट्यूरिंग थीसिस का समर्थन करता है, बल्कि नियतात्मक गणना पर लागू होने वाले विस्तारित (यानी, बहुपद) चर्च-ट्यूरिंग थीसिस का भी समर्थन करता है। दूसरे शब्दों में, इसमें बहुपद ओवरहेड है। वास्तव में, अगर हमें एक रैम मशीन या (मेरा व्यक्तिगत पसंदीदा) एक पेड़-टेप टीएम दिया जाता है, तो इसे रैम मेमोरी के साथ सीरियल कम्प्यूटेशन के लिए पॉलीग्लारिथमिक ओवरहेड में कम किया जा सकता है।