निरंतर-अग्रगामी शैली (सीपीएस): Difference between revisions

From Vigyanwiki
No edit summary
No edit summary
Line 1: Line 1:
{{Short description|Programming style in which control is passed explicitly}}
{{Short description|Programming style in which control is passed explicitly}}
[[कार्यात्मक प्रोग्रामिंग|फंक्शनल प्रोग्रामिंग]] में, निरंतरता-पासिंग शैली (सीपीएस) प्रोग्रामिंग की एक शैली है जिसमें नियंत्रण प्रवाह को निरंतरता के रूप में स्पष्ट रूप से पास्ड किया जाता है। इसकी तुलना प्रत्यक्ष शैली से की जाती है, जो की प्रोग्रामिंग की उसुअल शैली है। अतः [[गेराल्ड जे सुसमैन]] और गाइ एल. स्टील, जूनियर ने [[एआई मेमो]] 349 (1975) में वाक्यांश गढ़ा, जो स्कीम (प्रोग्रामिंग लैंग्वेज ) प्रोग्रामिंग लैंग्वेज का प्रथम वर्शन निर्धारित करता है।<ref>{{cite journal
[[कार्यात्मक प्रोग्रामिंग|फंक्शनल प्रोग्रामिंग]] में, निरंतर-अग्रगामी शैली (सीपीएस) प्रोग्रामिंग की शैली है जिसमें नियंत्रण प्रवाह को निरंतर के रूप में स्पष्ट रूप से पास्ड किया जाता है। इसकी तुलना प्रत्यक्ष शैली से की जाती है, जो की प्रोग्रामिंग की उसुअल शैली है। अतः [[गेराल्ड जे सुसमैन]] और गाइ एल. स्टील, जूनियर ने [[एआई मेमो]] 349 (1975) में वाक्यांश गढ़ा, जो स्कीम (प्रोग्रामिंग लैंग्वेज ) प्रोग्रामिंग लैंग्वेज का प्रथम वर्शन निर्धारित करता है।<ref>{{cite journal
| author1-link = Gerald Jay Sussman | first1 = Gerald Jay | last1 = Sussman | author2-link = Guy L. Steele, Jr. | first2 = Guy L., Jr. | last2 = Steele
| author1-link = Gerald Jay Sussman | first1 = Gerald Jay | last1 = Sussman | author2-link = Guy L. Steele, Jr. | first2 = Guy L., Jr. | last2 = Steele
|date=December 1975
|date=December 1975
Line 20: Line 20:
| pages = 405–439
| pages = 405–439
| s2cid = 18040106 | quote = We believe that this was the first occurrence of the term "'''continuation-passing style'''" in the literature. It has turned out to be an important concept in source code analysis and transformation for compilers and other metaprogramming tools. It has also inspired a set of other "styles" of program expression.
| s2cid = 18040106 | quote = We believe that this was the first occurrence of the term "'''continuation-passing style'''" in the literature. It has turned out to be an important concept in source code analysis and transformation for compilers and other metaprogramming tools. It has also inspired a set of other "styles" of program expression.
}}</ref> इस प्रकार से जॉन सी. रेनॉल्ड्स निरंतरता की अनेक खोजों का विस्तृत अकाउंट देते हैं।<ref>{{cite journal
}}</ref> इस प्रकार से जॉन सी. रेनॉल्ड्स निरंतर की अनेक खोजों का विस्तृत अकाउंट देते हैं।<ref>{{cite journal
|  author1-link    = John C. Reynolds | first1 = John C. | last1 = Reynolds
|  author1-link    = John C. Reynolds | first1 = John C. | last1 = Reynolds
| title    = The Discoveries of Continuations
| title    = The Discoveries of Continuations
Line 32: Line 32:
</ref>
</ref>


निरंतरता-पासिंग शैली में लिखा गया एक फ़ंक्शन एक्सप्लिसिट लॉजिक लेता है: एक स्पष्ट "निरंतरता"; अर्थात , एक लॉजिक का एक कार्य: और स्पष्ट निरंतरता; अर्थात लॉजिक का कार्य है। जब सीपीएस फ़ंक्शन ने अपने परिणाम मान की गणना की है, तो यह लॉजिक के रूप में इस मान के साथ निरंतरता फ़ंक्शन को कॉल करके इसे वापस कर देता है। इसका अर्थ यह है कि सीपीएस फ़ंक्शन को प्रयुक्त करते समय, कॉलिंग फ़ंक्शन को सबरूटीन के रिटर्न वैल्यू के साथ प्रयुक्त करने के लिए प्रोसीजर प्रदान करने की आवश्यकता होती है। अतः कोड को इस रूप में व्यक्त करने से अनेक वस्तु स्पष्ट हो जाती हैं जो की प्रत्यक्ष शैली में अंतर्निहित होती हैं। इनमें सम्मिलित हैं: इस प्रकार से प्रोसीजर रिटर्न, जो निरंतरता के लिए कॉल के रूप में स्पष्ट हो जाते हैं; इंटरमीडिएट मान, जो सभी दिए गए नाम हैं; लॉजिक इवैल्यूएशन का क्रम, जिसे स्पष्ट किया गया है; और [[ पूंछ कॉल |टेल कॉल]] , जो बस उसी निरंतरता के साथ प्रोसीजर को कॉल करते हैं, जो उनमोडीफ़िएड, कॉलर को दी गई थी।
निरंतर-अग्रगामी शैली में लिखा गया फ़ंक्शन एक्सप्लिसिट लॉजिक लेता है: स्पष्ट "निरंतर"; अर्थात , लॉजिक का कार्य: और स्पष्ट निरंतर; अर्थात लॉजिक का कार्य है। जब सीपीएस फ़ंक्शन ने अपने परिणाम मान की गणना की है, तो यह लॉजिक के रूप में इस मान के साथ निरंतर फ़ंक्शन को कॉल करके इसे वापस कर देता है। इसका अर्थ यह है कि सीपीएस फ़ंक्शन को प्रयुक्त करते समय, कॉलिंग फ़ंक्शन को सबरूटीन के रिटर्न वैल्यू के साथ प्रयुक्त करने के लिए प्रोसीजर प्रदान करने की आवश्यकता होती है। अतः कोड को इस रूप में व्यक्त करने से अनेक वस्तु स्पष्ट हो जाती हैं जो की प्रत्यक्ष शैली में अंतर्निहित होती हैं। इनमें सम्मिलित हैं: इस प्रकार से प्रोसीजर रिटर्न, जो निरंतर के लिए कॉल के रूप में स्पष्ट हो जाते हैं; इंटरमीडिएट मान, जो सभी दिए गए नाम हैं; लॉजिक इवैल्यूएशन का क्रम, जिसे स्पष्ट किया गया है; और [[ पूंछ कॉल |टेल कॉल]] , जो बस उसी निरंतर के साथ प्रोसीजर को कॉल करते हैं, जो उनमोडीफ़िएड, कॉलर को दी गई थी।


प्रोग्राम को स्वचालित रूप से डायरेक्ट स्टाइल से सीपीएस में परिवर्तन किया जा सकता है। और फंक्शनल और लॉजिक [[तर्क प्रोग्रामिंग|प्रोग्रामिंग]] कंपाइलर प्रायः सीपीएस को [[मध्यवर्ती प्रतिनिधित्व|इंटरमीडिएट रिप्रजेंटेशन]] के रूप में उपयोग करते हैं जहां [[अनिवार्य प्रोग्रामिंग|इम्पेरेटिव प्रोग्रामिंग]] या [[प्रक्रियात्मक प्रोग्रामिंग|प्रोसीज़रल प्रोग्रामिंग]] लैंग्वेज के लिए कंपाइलर [[स्थिर एकल असाइनमेंट फॉर्म|ए असाइनमेंट फॉर्म]] (एसएसए) का उपयोग किया जाता है।<ref name="Appel1998">*{{cite journal | first = Andrew W. | last = Appel | title=SSA is Functional Programming | journal=ACM SIGPLAN Notices | date=April 1998 | volume=33 | issue = 4 | pages=17–20 | doi = 10.1145/278283.278285 | citeseerx = 10.1.1.34.3282 | s2cid = 207227209 }}</ref> इस प्रकार से एसएसए औपचारिक रूप से सीपीएस के सबसेट के समान है (नॉन-लोकल कण्ट्रोल फ्लो को छोड़कर, जो तब नहीं होता है जब सीपीएस को [[मध्यवर्ती प्रतिनिधित्व|इंटरमीडिएट]] रिप्रजेंटेशन के रूप में उपयोग किया जाता है)।<ref name="Kelsey1995">*{{cite journal | first = Richard A. | last = Kelsey | title=A Correspondence between Continuation Passing Style and Static Single Assignment Form | journal=ACM SIGPLAN Notices |date=March 1995 | volume=30 | issue=3  | pages=13–22 | doi=10.1145/202530.202532| citeseerx = 10.1.1.489.930 }}</ref> इस प्रकार से फंक्शनल [[ संकलक |कंपाइलर]] सीपीएस में '[[थंक (विलंबित गणना)]]' (नीचे दिए गए उदाहरणों में वर्णित) के अतिरिक्त ए-नार्मल फॉर्म (एएनएफ) (किन्तु केवल उत्सुक इवैल्यूएशन की आवश्यकता वाली लैंग्वेज के लिए) का उपयोग कर सकते हैं। अतः सीपीएस का उपयोग स्थानीय या ग्लोबल शैली के रूप में प्रोग्रामर की तुलना में कंपाइलरों द्वारा अधिक बार किया जाता है।
प्रोग्राम को स्वचालित रूप से डायरेक्ट स्टाइल से सीपीएस में परिवर्तन किया जा सकता है। और फंक्शनल और लॉजिक [[तर्क प्रोग्रामिंग|प्रोग्रामिंग]] कंपाइलर प्रायः सीपीएस को [[मध्यवर्ती प्रतिनिधित्व|इंटरमीडिएट रिप्रजेंटेशन]] के रूप में उपयोग करते हैं जहां [[अनिवार्य प्रोग्रामिंग|इम्पेरेटिव प्रोग्रामिंग]] या [[प्रक्रियात्मक प्रोग्रामिंग|प्रोसीज़रल प्रोग्रामिंग]] लैंग्वेज के लिए कंपाइलर [[स्थिर एकल असाइनमेंट फॉर्म|ए असाइनमेंट फॉर्म]] (एसएसए) का उपयोग किया जाता है।<ref name="Appel1998">*{{cite journal | first = Andrew W. | last = Appel | title=SSA is Functional Programming | journal=ACM SIGPLAN Notices | date=April 1998 | volume=33 | issue = 4 | pages=17–20 | doi = 10.1145/278283.278285 | citeseerx = 10.1.1.34.3282 | s2cid = 207227209 }}</ref> इस प्रकार से एसएसए औपचारिक रूप से सीपीएस के सबसेट के समान है (नॉन-लोकल कण्ट्रोल फ्लो को छोड़कर, जो तब नहीं होता है जब सीपीएस को [[मध्यवर्ती प्रतिनिधित्व|इंटरमीडिएट]] रिप्रजेंटेशन के रूप में उपयोग किया जाता है)।<ref name="Kelsey1995">*{{cite journal | first = Richard A. | last = Kelsey | title=A Correspondence between Continuation Passing Style and Static Single Assignment Form | journal=ACM SIGPLAN Notices |date=March 1995 | volume=30 | issue=3  | pages=13–22 | doi=10.1145/202530.202532| citeseerx = 10.1.1.489.930 }}</ref> इस प्रकार से फंक्शनल [[ संकलक |कंपाइलर]] सीपीएस में '[[थंक (विलंबित गणना)]]' (नीचे दिए गए उदाहरणों में वर्णित) के अतिरिक्त ए-नार्मल फॉर्म (एएनएफ) (किन्तु केवल उत्सुक इवैल्यूएशन की आवश्यकता वाली लैंग्वेज के लिए) का उपयोग कर सकते हैं। अतः सीपीएस का उपयोग स्थानीय या ग्लोबल शैली के रूप में प्रोग्रामर की तुलना में कंपाइलरों द्वारा अधिक बार किया जाता है।


==उदाहरण==
==उदाहरण==
इस प्रकार से सीपीएस में, प्रत्येक प्रोसीजर एक्स्ट्रा लॉजिक प्राप्त करती है जो यह दर्शाती है कि फ़ंक्शन द्वारा गणना किए जा रहे परिणाम के साथ क्या किया जाना चाहिए। यह, सामान्यतः उपलब्ध विभिन्न प्रकार के निर्माणों को प्रतिबंधित करने वाली रेस्ट्रिक्टिव शैली के साथ, प्रोग्राम के शब्दार्थ को उजागर करने के लिए उपयोग किया जाता है, जिससे उनका विश्लेषण करना सरल हो जाता है। यह शैली असामान्य नियंत्रण स्ट्रूकचर को जैसे कैच/थ्रो या नियंत्रण के अन्य नॉन-लोकल ट्रांस्फर्स व्यक्त करना भी सरल बनाती है।
इस प्रकार से सीपीएस में, प्रत्येक प्रोसीजर एक्स्ट्रा लॉजिक प्राप्त करती है जो यह दर्शाती है कि फ़ंक्शन द्वारा गणना किए जा रहे परिणाम के साथ क्या किया जाना चाहिए। यह, सामान्यतः उपलब्ध विभिन्न प्रकार के निर्माणों को प्रतिबंधित करने वाली रेस्ट्रिक्टिव शैली के साथ, प्रोग्राम के शब्दार्थ को उजागर करने के लिए उपयोग किया जाता है, जिससे उनका विश्लेषण करना सरल हो जाता है। यह शैली असामान्य नियंत्रण स्ट्रूकवेरिएबल को जैसे कैच/थ्रो या नियंत्रण के अन्य नॉन-लोकल ट्रांस्फर्स व्यक्त करना भी सरल बनाती है।


अतः सीपीएस की कुंजी यह याद रखना है कि (a) प्रत्येक फ़ंक्शन एक्स्ट्रा लॉजिक लेता है जिसे इसकी निरंतरता के रूप में जाना जाता है, और (b) फ़ंक्शन कॉल में प्रत्येक लॉजिक या तो चर या [[लैम्ब्डा (प्रोग्रामिंग)]] होना चाहिए (अधिक सम्मिश्र अभिव्यक्ति नहीं)। इसमें अभिव्यक्ति को इनसाइड-आउट   करने का प्रभाव होता है क्योंकि अभिव्यक्ति के सबसे इनरमोस्ट पार्ट्स का इवैल्यूएशन पहले किया जाना चाहिए, चूंकि इस प्रकार सीपीएस इवैल्यूएशन के क्रम के साथ-साथ नियंत्रण प्रवाह को भी स्पष्ट करता है। प्रत्यक्ष शैली में कोड और संबंधित सीपीएस के कुछ उदाहरण नीचे दिखाई देते हैं। ये उदाहरण योजना (प्रोग्रामिंग लैंग्वेज) में लिखे गए हैं; प्रिमिटीव्स के अनुसार निरंतरता फ़ंक्शन <code>k</code>: को नामित पैरामीटर के रूप में दर्शाया जाता है
अतः सीपीएस की कुंजी यह याद रखना है कि (a) प्रत्येक फ़ंक्शन एक्स्ट्रा लॉजिक लेता है जिसे इसकी निरंतर के रूप में जाना जाता है, और (b) फ़ंक्शन कॉल में प्रत्येक लॉजिक या तो वेरिएबल या [[लैम्ब्डा (प्रोग्रामिंग)]] होना चाहिए (अधिक सम्मिश्र अभिव्यक्ति नहीं)। इसमें अभिव्यक्ति को इनसाइड-आउट करने का प्रभाव होता है क्योंकि अभिव्यक्ति के सबसे इनरमोस्ट पार्ट्स का इवैल्यूएशन पहले किया जाना चाहिए, चूंकि इस प्रकार सीपीएस इवैल्यूएशन के क्रम के साथ-साथ नियंत्रण प्रवाह को भी स्पष्ट करता है। प्रत्यक्ष शैली में कोड और संबंधित सीपीएस के कुछ उदाहरण नीचे दिखाई देते हैं। ये उदाहरण योजना (प्रोग्रामिंग लैंग्वेज) में लिखे गए हैं; प्रिमिटीव्स के अनुसार निरंतर फ़ंक्शन <code>k</code>: को नामित पैरामीटर के रूप में दर्शाया जाता है
{|
{|
!{{center|Direct style}}!!{{center|Continuation passing style}}
!{{center|Direct style}}!!{{center|Continuation passing style}}
Line 95: Line 95:
</syntaxhighlight>
</syntaxhighlight>
|}
|}
ध्यान दें कि सीपीएस वर्शन में, प्रिमिटीव्स का उपयोग किया जाता है, जैसे <code>+&</code> और <code>*&</code> स्वयं सीपीएस हैं, प्रत्यक्ष शैली नहीं है, इसलिए उपरोक्त उदाहरणों को स्कीम सिस्टम में कार्य करने के लिए हमें प्रिमिटीव्स के इन सीपीएस वर्शन को लिखने की आवश्यकता होती है, उदाहरण के लिए <code>*&</code> द्वारा परिभाषित:
ध्यान दें कि सीपीएस वर्शन में, प्रिमिटीव्स का उपयोग किया जाता है, जैसे <code>+&</code> और <code>*&</code> स्वयं सीपीएस हैं, प्रत्यक्ष शैली नहीं है, इसलिए उपरोक्त उदाहरणों को स्कीम सिस्टम में कार्य करने के लिए हमें प्रिमिटीव्स के इन सीपीएस वर्शन को लिखने की आवश्यकता होती है, उदाहरण के लिए <code>*&</code> द्वारा परिभाषित:
<syntaxhighlight lang=scheme>
<syntaxhighlight lang=scheme>
(define (*& x y k)
(define (*& x y k)
Line 108: Line 108:
(define *& (cps-prim *))
(define *& (cps-prim *))
(define +& (cps-prim +))</syntaxhighlight>
(define +& (cps-prim +))</syntaxhighlight>
इस प्रकार से सीपीएस में लिखी गई प्रोसीजर को प्रत्यक्ष शैली में लिखी गई प्रोसीजर से कॉल करने के लिए, निरंतरता प्रदान करना आवश्यक है जो की सीपीएस प्रोसीजर द्वारा गणना किए गए परिणाम प्राप्त करती है। अतः उपरोक्त उदाहरण में (यह मानते हुए कि सीपीएस प्राइमेटिव्स प्रदान किए गए हैं), हम कॉल कर सकते हैं <code>(factorial& 10 (lambda (x) (display x) (newline)))</code>.
इस प्रकार से सीपीएस में लिखी गई प्रोसीजर को प्रत्यक्ष शैली में लिखी गई प्रोसीजर से कॉल करने के लिए, निरंतर प्रदान करना आवश्यक है जो की सीपीएस प्रोसीजर द्वारा गणना किए गए परिणाम प्राप्त करती है। अतः उपरोक्त उदाहरण में (यह मानते हुए कि सीपीएस प्राइमेटिव्स प्रदान किए गए हैं), हम कॉल कर सकते हैं <code>(factorial& 10 (lambda (x) (display x) (newline)))</code>.


अतः सीपीएस में प्रिमिटीव्स कार्य प्रदान करने के विधि में कंपाइलरों के मध्य कुछ विविधता है। ऊपर हमने सबसे सिम्प्लेस्ट कन्वेंशन का उपयोग किया है, चूंकि कभी-कभी बूलियन प्राइमेटिव प्रदान किए जाते हैं जो दो संभावित स्तिथियों में कॉल करने के लिए दो थंक (विलंबित गणना) लेते हैं, इसलिए <code>(=& n 0 (lambda (b) (if b ...)))</code> अंदर कॉल करें <code>f-aux&</code> उपरोक्त परिभाषा के स्थान पर इस प्रकार कॉन्टीनुएशन   <code>(=& n 0 (lambda () (k a)) (lambda () (-& n 1 ...)))</code>. लिखा जाएगा इसी तरह, कभी-कभी <code>if</code> प्रिमिटिव स्वयं सीपीएस में सम्मिलित नहीं है, किन्तु फ़ंक्शन <code>if&</code> है प्रदान किया जाता है जिसमें तीन लॉजिक होते हैं: बूलियन स्थिति और सशर्त की दो आर्म्स के अनुरूप दो थंक आदि।
अतः सीपीएस में प्रिमिटीव्स कार्य प्रदान करने के विधि में कंपाइलरों के मध्य कुछ विविधता है। ऊपर हमने सबसे सिम्प्लेस्ट कन्वेंशन का उपयोग किया है, चूंकि कभी-कभी बूलियन प्राइमेटिव प्रदान किए जाते हैं जो दो संभावित स्तिथियों में कॉल करने के लिए दो थंक (विलंबित गणना) लेते हैं, इसलिए <code>(=& n 0 (lambda (b) (if b ...)))</code> अंदर कॉल करें <code>f-aux&</code> उपरोक्त परिभाषा के स्थान पर इस प्रकार कॉन्टीनुएशन <code>(=& n 0 (lambda () (k a)) (lambda () (-& n 1 ...)))</code>. लिखा जाएगा इसी तरह, कभी-कभी <code>if</code> प्रिमिटिव स्वयं सीपीएस में सम्मिलित नहीं है, किन्तु फ़ंक्शन <code>if&</code> है प्रदान किया जाता है जिसमें तीन लॉजिक होते हैं: बूलियन स्थिति और सशर्त की दो आर्म्स के अनुरूप दो थंक आदि।


ऊपर दिखाए गए अनुवाद दर्शाया गया हैं कि सीपीएस ग्लोबल परिवर्तन है। जैसी कि अपेक्षा की जा सकती है, प्रत्यक्ष शैली का फैक्टोरियल ही लॉजिक प्राप्त करता है; इस प्रकार से लॉजिक और निरंतरता सीपीएस फैक्टोरियल टू प्राप्त करता है: अतः सीपीएस-एड फ़ंक्शन को कॉल करने वाले किसी भी फ़ंक्शन को या तो नई निरंतरता प्रदान करनी होगी या अपना स्वयं का पास करना होगा; सीपीएस-एड फ़ंक्शन से नॉन-सीपीएस फ़ंक्शन में कोई भी कॉल अंतर्निहित निरंतरता का उपयोग करती है। इस प्रकार, फ़ंक्शन स्टैक की पूर्ण अनुपस्थिति सुनिश्चित करने के लिए, एंटीरे प्रोग्राम सीपीएस में होना चाहिए।
ऊपर दिखाए गए अनुवाद दर्शाया गया हैं कि सीपीएस ग्लोबल परिवर्तन है। जैसी कि अपेक्षा की जा सकती है, प्रत्यक्ष शैली का फैक्टोरियल ही लॉजिक प्राप्त करता है; इस प्रकार से लॉजिक और निरंतर सीपीएस फैक्टोरियल टू प्राप्त करता है: अतः सीपीएस-एड फ़ंक्शन को कॉल करने वाले किसी भी फ़ंक्शन को या तो नई निरंतर प्रदान करनी होगी या अपना स्वयं का पास करना होगा; सीपीएस-एड फ़ंक्शन से नॉन-सीपीएस फ़ंक्शन में कोई भी कॉल अंतर्निहित निरंतर का उपयोग करती है। इस प्रकार, फ़ंक्शन स्टैक की पूर्ण अनुपस्थिति सुनिश्चित करने के लिए, एंटीरे प्रोग्राम सीपीएस में होना चाहिए।


===हास्केल में सीपीएस (प्रोग्रामिंग लैंग्वेज)===
===हास्केल में सीपीएस (प्रोग्रामिंग लैंग्वेज)===
इस अनुभाग में हम फ़ंक्शन लिखेंगे <code>pyth</code> जो [[पाइथागोरस प्रमेय]] का उपयोग करके कर्ण की गणना करता है। और <code>pyth</code> ट्रेडिशनल इम्प्लीमेंटेशन फ़ंक्शन इस तरह दिखता है:
इस अनुभाग में हम फ़ंक्शन लिखेंगे <code>pyth</code> जो [[पाइथागोरस प्रमेय]] का उपयोग करके कर्ण की गणना करता है। और <code>pyth</code> ट्रेडिशनल इम्प्लीमेंटेशन फ़ंक्शन इस तरह दिखता है:
<syntaxhighlight lang="haskell">
<syntaxhighlight lang="haskell">
pow2 :: Float -> Float
pow2 :: Float -> Float
Line 126: Line 126:
pyth x y = sqrt (add (pow2 x) (pow2 y))
pyth x y = sqrt (add (pow2 x) (pow2 y))
</syntaxhighlight>
</syntaxhighlight>
ट्रेडिशनल फ़ंक्शन को सीपीएस में परिवर्तन के लिए, हमें इसके सिग्नेचर  को परिवर्तन की आवश्यकता है। फ़ंक्शन को फ़ंक्शन प्रकार का और लॉजिक प्राप्त होगा, और इसका रिटर्न प्रकार उस फ़ंक्शन पर निर्भर करता है:
ट्रेडिशनल फ़ंक्शन को सीपीएस में परिवर्तन के लिए, हमें इसके सिग्नेवेरिएबल को परिवर्तन की आवश्यकता है। फ़ंक्शन को फ़ंक्शन प्रकार का और लॉजिक प्राप्त होगा, और इसका रिटर्न प्रकार उस फ़ंक्शन पर निर्भर करता है:
<syntaxhighlight lang="haskell">
<syntaxhighlight lang="haskell">
pow2' :: Float -> (Float -> a) -> a
pow2' :: Float -> (Float -> a) -> a
Line 142: Line 142:
pyth' x y cont = pow2' x (\x2 -> pow2' y (\y2 -> add' x2 y2 (\anb -> sqrt' anb cont)))
pyth' x y cont = pow2' x (\x2 -> pow2' y (\y2 -> add' x2 y2 (\anb -> sqrt' anb cont)))
</syntaxhighlight>
</syntaxhighlight>
सर्वप्रथम हम <code>pyth'</code> फ़ंक्शन में a के वर्ग की गणना करते हैं और एक लैम्ब्डा फ़ंक्शन को निरंतरता के रूप में पास करते हैं जो प्रथम लॉजिक के रूप में a के वर्ग को स्वीकार करेगा। और इसी तरह जब तक हम अपनी गणना के परिणाम तक नहीं पहुंच जाते, इस फ़ंक्शन का परिणाम प्राप्त करने के लिए हम <code>id</code> फ़ंक्शन को अंतिम लॉजिक के रूप में पास कर सकते हैं, जो उसे दिए गए मान <code>pyth' 3 4 id == 5.0 को अपरिवर्तित रिटर्निंग करता है:</code>
सर्वप्रथम हम <code>pyth'</code> फ़ंक्शन में a के वर्ग की गणना करते हैं और लैम्ब्डा फ़ंक्शन को निरंतर के रूप में पास करते हैं जो प्रथम लॉजिक के रूप में a के वर्ग को स्वीकार करेगा। और इसी तरह जब तक हम अपनी गणना के परिणाम तक नहीं पहुंच जाते, इस फ़ंक्शन का परिणाम प्राप्त करने के लिए हम <code>id</code> फ़ंक्शन को अंतिम लॉजिक के रूप में पास कर सकते हैं, जो उसे दिए गए मान <code>pyth' 3 4 id == 5.0 को अपरिवर्तित रिटर्निंग करता है:</code>


एमटीएल लाइब्रेरी, जिसे [[ग्लासगो हास्केल कंपाइलर]] के साथ भेजा जाता है, में <code>Control.Monad.Cont</code>. मॉड्यूल है यह मॉड्यूल कॉन्ट प्रकार प्रदान करता है, जो मोनाड और कुछ अन्य उपयोगी कार्यों को प्रयुक्त करता है। निम्नलिखित स्निपेट कंट का उपयोग करके <code>pyth'</code> ' फ़ंक्शन दिखाता है: <syntaxhighlight lang="haskell">
एमटीएल लाइब्रेरी, जिसे [[ग्लासगो हास्केल कंपाइलर]] के साथ भेजा जाता है, में <code>Control.Monad.Cont</code>. मॉड्यूल है यह मॉड्यूल कॉन्ट प्रकार प्रदान करता है, जो मोनाड और कुछ अन्य उपयोगी कार्यों को प्रयुक्त करता है। निम्नलिखित स्निपेट कंट का उपयोग करके <code>pyth'</code> ' फ़ंक्शन दिखाता है: <syntaxhighlight lang="haskell">
pow2_m :: Float -> Cont a Float
pow2_m :: Float -> Cont a Float
pow2_m a = return (a ** 2)
pow2_m a = return (a ** 2)
Line 156: Line 156:
   return r
   return r
</syntaxhighlight>
</syntaxhighlight>
इस प्रकार से न केवल सिंटैक्स क्लीनर है, किन्तु यह प्रकार हमें <code>MonadCont m => ((a -> m b) -> m a) -> m a</code>. प्रकार के साथ फ़ंक्शन <code>callCC</code> का उपयोग करने की अनुमति देता है। इस फ़ंक्शन में फ़ंक्शन प्रकार का एक लॉजिक होता है; वह फ़ंक्शन लॉजिक फ़ंक्शन को भी स्वीकार करता है, जो उसके कॉल के पश्चात होने वाली सभी गणनाओं को छोड़ देता है। उदाहरण के लिए, आइए <code>pyth</code> फ़ंक्शन के निष्पादन को तोड़ दें यदि इसका कम से कम एक लॉजिक ऋणात्मक है और शून्य रिटर्निंग कर रहा है:
इस प्रकार से न केवल सिंटैक्स क्लीनर है, किन्तु यह प्रकार हमें <code>MonadCont m => ((a -> m b) -> m a) -> m a</code>. प्रकार के साथ फ़ंक्शन <code>callCC</code> का उपयोग करने की अनुमति देता है। इस फ़ंक्शन में फ़ंक्शन प्रकार का लॉजिक होता है; वह फ़ंक्शन लॉजिक फ़ंक्शन को भी स्वीकार करता है, जो उसके कॉल के पश्चात होने वाली सभी गणनाओं को छोड़ देता है। उदाहरण के लिए, आइए <code>pyth</code> फ़ंक्शन के निष्पादन को अंत कर दें यदि इसका कम से कम लॉजिक ऋणात्मक है और शून्य रिटर्निंग कर रहा है:
<syntaxhighlight lang="haskell">
<syntaxhighlight lang="haskell">
pyth_m :: Float -> Float -> Cont a Float
pyth_m :: Float -> Float -> Cont a Float
Line 169: Line 169:




===ऑब्जेक्टस   के रूप में निरंतरता===
===ऑब्जेक्टस के रूप में निरंतर===
{{See also|कॉलबैक (कंप्यूटर प्रोग्रामिंग)}}
{{See also|कॉलबैक (कंप्यूटर प्रोग्रामिंग)}}


निरंतरता के साथ प्रोग्रामिंग तब भी उपयोगी हो सकती है जब कोई कॉल करने वाला कॉल पूरा होने तक वेट नहीं करना चाहता है। इस प्रकार से उदाहरण के लिए, यूजर-इंटरफ़ेस (यूआई) प्रोग्रामिंग में, रूटीन डायलॉग बॉक्स फ़ील्ड सेट कर सकता है और इन्हें निरंतरता फ़ंक्शन के साथ यूआई फ्रेमवर्क में पास कर सकता है। यह कॉल तुरंत रिटर्न आती है, जिससे एप्लिकेशन कोड तब तक प्रवाहित रहता है जब तक उपयोगकर्ता डायलॉग बॉक्स के साथ इंटरैक्ट करता है। बार जब उपयोगकर्ता "ओके" बटन दबाता है, तो फ्रेमवर्क अपडेटेड फ़ील्ड के साथ निरंतरता फ़ंक्शन को कॉल करता है। चूंकि कोडिंग की यह शैली निरंतरता का उपयोग करती है, यह पूर्ण सीपीएस नहीं है।
निरंतर के साथ प्रोग्रामिंग तब भी उपयोगी हो सकती है जब कोई कॉल करने वाला कॉल पूरा होने तक वेट नहीं करना चाहता है। इस प्रकार से उदाहरण के लिए, यूजर-इंटरफ़ेस (यूआई) प्रोग्रामिंग में, रूटीन डायलॉग बॉक्स फ़ील्ड सेट कर सकता है और इन्हें निरंतर फ़ंक्शन के साथ यूआई फ्रेमवर्क में पास कर सकता है। यह कॉल तुरंत रिटर्न आती है, जिससे एप्लिकेशन कोड तब तक निरंतर रहता है जब तक उपयोगकर्ता डायलॉग बॉक्स के साथ इंटरैक्ट करता है। बार जब उपयोगकर्ता "ओके" बटन दबाता है, तो फ्रेमवर्क अपडेटेड फ़ील्ड के साथ निरंतर फ़ंक्शन को कॉल करता है। चूंकि कोडिंग की यह शैली निरंतर का उपयोग करती है, यह पूर्ण सीपीएस नहीं है।


<syntaxhighlight lang=javascript>
<syntaxhighlight lang=javascript>
Line 184: Line 184:
}
}
</syntaxhighlight>
</syntaxhighlight>
एक समान विचार का उपयोग तब किया जा सकता है जब फ़ंक्शन को किसी डिफरेंट थ्रेड में या किसी डिफरेंट प्रोसेसर पर चलाना होता है। फ्रेमवर्क वर्कर थ्रेड में कॉल किए गए फ़ंक्शन को निष्पादित कर सकता है, फिर वर्कर के परिणामों के साथ मूल थ्रेड में निरंतरता फ़ंक्शन को कॉल कर सकता है। यह [[जावा (प्रोग्रामिंग भाषा)|जावा 8 (प्रोग्रामिंग लैंग्वेज)]] में [[स्विंग (जावा)]] यूआई फ्रेमवर्क का उपयोग कर रहा है:
समान विचार का उपयोग तब किया जा सकता है जब फ़ंक्शन को किसी डिफरेंट थ्रेड में या किसी डिफरेंट प्रोसेसर पर चलाना होता है। फ्रेमवर्क वर्कर थ्रेड में कॉल किए गए फ़ंक्शन को निष्पादित कर सकता है, फिर वर्कर के परिणामों के साथ मूल थ्रेड में निरंतर फ़ंक्शन को कॉल कर सकता है। यह [[जावा (प्रोग्रामिंग भाषा)|जावा 8 (प्रोग्रामिंग लैंग्वेज)]] में [[स्विंग (जावा)]] यूआई फ्रेमवर्क का उपयोग कर रहा है:


<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
Line 209: Line 209:


==टेल कॉल==
==टेल कॉल==
सीपीएस में प्रत्येक कॉल टेल कॉल है, और निरंतरता स्पष्ट रूप से पारित की जाती है। [[टेल कॉल अनुकूलन]] (टीसीओ) के बिना सीपीएस का उपयोग करने से रिकर्सन के समय न केवल निर्मित निरंतरता संभावित रूप से बढ़ेगी, किन्तु [[कॉल स्टैक]] भी बढ़ता है। यह सामान्यतः उन्देसिरबले  है, किन्तु इसका उपयोग (योजना इम्प्लीमेंटेशन ) या चिकन स्कीम कंपाइलर अर्थात रोचक विधियों से किया गया है। चूंकि सीपीएस और टीसीओ अंतर्निहित फ़ंक्शन रिटर्न की अवधारणा को समाप्त करते हैं, उनका संयुक्त उपयोग रन-टाइम स्टैक की आवश्यकता को समाप्त कर सकता है। अतः [[कार्यात्मक प्रोग्रामिंग भाषा|फंक्शनल प्रोग्रामिंग]] लैंग्वेज के लिए अनेक कंपाइलर और इनटरप्रेटर्शिप नए विधियों से इस क्षमता का उपयोग करते हैं।<ref>Appel, Andrew W. (1992). Compiling with Continuations. Cambridge University Press. {{ISBN|0-521-41695-7}}.</ref>
सीपीएस में प्रत्येक कॉल टेल कॉल है, और निरंतर स्पष्ट रूप से पारित की जाती है। [[टेल कॉल अनुकूलन]] (टीसीओ) के बिना सीपीएस का उपयोग करने से रिकर्सन के समय न केवल निर्मित निरंतर संभावित रूप से बढ़ेगी, किन्तु [[कॉल स्टैक]] भी बढ़ता है। यह सामान्यतः अनिष्ट है, किन्तु इसका उपयोग (योजना इम्प्लीमेंटेशन ) या चिकन स्कीम कंपाइलर अर्थात रोचक विधियों से किया गया है। चूंकि सीपीएस और टीसीओ अंतर्निहित फ़ंक्शन रिटर्न की अवधारणा को समाप्त करते हैं, उनका संयुक्त उपयोग रन-टाइम स्टैक की आवश्यकता को समाप्त कर सकता है। अतः [[कार्यात्मक प्रोग्रामिंग भाषा|फंक्शनल प्रोग्रामिंग]] लैंग्वेज के लिए अनेक कंपाइलर और इनटरप्रेटर्शिप नए विधियों से इस क्षमता का उपयोग करते हैं।<ref>Appel, Andrew W. (1992). Compiling with Continuations. Cambridge University Press. {{ISBN|0-521-41695-7}}.</ref>
==उपयोग और इम्प्लीमेंटेशन ==
==उपयोग और इम्प्लीमेंटेशन ==
[[निरंतरता]] पासिंग शैली का उपयोग फंक्शनल लैंग्वेज में निरंतरता को प्रयुक्त करने और प्रवाह ऑपरेटरों को नियंत्रित करने के लिए किया जा सकता है जिसमें प्रथम श्रेणी की निरंतरता की सुविधा नहीं है किन्तु प्रथम श्रेणी के फ़ंक्शन और [[टेल-कॉल अनुकूलन]] हैं। टेल-कॉल ऑप्टिमाइज़ेशन के बिना, [[ट्रैम्पोलिन (कंप्यूटर)]] जैसी तकनीकों का उपयोग किया जा सकता है, अर्थात लूप का उपयोग करना जो पुनरावृत्त रूप से [[थंक (कार्यात्मक प्रोग्रामिंग)|थंक ( फंक्शनल प्रोग्रामिंग)]]-रिटर्निंग फ़ंक्शंस को आमंत्रित करता है; प्रथम श्रेणी के फ़ंक्शंस के बिना, ऐसे लूप में टेल कॉल को केवल गोटो में परिवर्तित करना भी संभव है।
[[निरंतरता|निरंतर]] अग्रगामी शैली का उपयोग फंक्शनल लैंग्वेज में निरंतर को प्रयुक्त करने और प्रवाह ऑपरेटरों को नियंत्रित करने के लिए किया जा सकता है जिसमें प्रथम श्रेणी की निरंतर की सुविधा नहीं है किन्तु प्रथम श्रेणी के फ़ंक्शन और [[टेल-कॉल अनुकूलन]] हैं। टेल-कॉल ऑप्टिमाइज़ेशन के बिना, [[ट्रैम्पोलिन (कंप्यूटर)]] जैसी तकनीकों का उपयोग किया जा सकता है, अर्थात लूप का उपयोग करना जो पुनरावृत्त रूप से [[थंक (कार्यात्मक प्रोग्रामिंग)|थंक ( फंक्शनल प्रोग्रामिंग)]]-रिटर्निंग फ़ंक्शंस को आमंत्रित करता है; प्रथम श्रेणी के फ़ंक्शंस के बिना, ऐसे लूप में टेल कॉल को केवल गोटो में परिवर्तित करना भी संभव है।


इस प्रकार से सीपीएस में कोड लिखना, चूंकि असंभव नहीं है, प्रायः एरर-प्रोन होता है। विभिन्न अनुवाद हैं, जिन्हें सामान्यतः शुद्ध [[लैम्ब्डा कैलकुलस]] के या दो-पास रूपांतरण के रूप में परिभाषित किया जाता है, जो प्रत्यक्ष शैली अभिव्यक्तियों को सीपीएस अभिव्यक्तियों में परिवर्तित करता है। चूंकि , ट्रम्पोलिन्ड शैली में लिखना अत्यंत कठिन है; जब उपयोग किया जाता है, तो यह सामान्यतः किसी प्रकार के परिवर्तन का लक्ष्य होता है, जैसे कि कंपाइलर आदि।
इस प्रकार से सीपीएस में कोड लिखना, चूंकि असंभव नहीं है, प्रायः एरर-प्रोन होता है। विभिन्न अनुवाद हैं, जिन्हें सामान्यतः शुद्ध [[लैम्ब्डा कैलकुलस]] के या दो-पास रूपांतरण के रूप में परिभाषित किया जाता है, जो प्रत्यक्ष शैली अभिव्यक्तियों को सीपीएस अभिव्यक्तियों में परिवर्तित करता है। चूंकि , ट्रम्पोलिन्ड शैली में लिखना अत्यंत कठिन है; जब उपयोग किया जाता है, तो यह सामान्यतः किसी प्रकार के परिवर्तन का लक्ष्य होता है, जैसे कि कंपाइलर आदि।


एक से अधिक निरंतरता का उपयोग करने वाले कार्यों को विभिन्न नियंत्रण प्रवाह प्रतिमानों को कैप्चर के लिए परिभाषित किया जा सकता है, उदाहरण के लिए (स्कीम (प्रोग्रामिंग लैंग्वेज) में) है:
एक से अधिक निरंतर का उपयोग करने वाले कार्यों को विभिन्न नियंत्रण प्रवाह प्रतिमानों को कैप्वेरिएबल के लिए परिभाषित किया जा सकता है, उदाहरण के लिए (स्कीम (प्रोग्रामिंग लैंग्वेज) में) है:
<syntaxhighlight lang=scheme>
<syntaxhighlight lang=scheme>
(define (/& x y ok err)
(define (/& x y ok err)
Line 225: Line 225:
यह ध्यान देने वाली तथ्य है कि सीपीएस परिवर्तन वैचारिक रूप से [[योनेडा एम्बेडिंग]] है।<ref>Mike Stay, [http://golem.ph.utexas.edu/category/2008/01/the_continuation_passing_trans.html "The Continuation Passing Transform and the Yoneda Embedding"]</ref> यह π-कैलकुलस में लैम्ब्डा कैलकुलस के एम्बेडिंग के समान है।<ref>Mike Stay, [http://golem.ph.utexas.edu/category/2009/09/the_pi_calculus_ii.html "The Pi Calculus II"]</ref><ref>{{cite CiteSeerX | first = Gérard | last = Boudol | citeseerx = 10.1.1.52.6034 | title = The π-Calculus in Direct Style | year = 1997 }}</ref>
यह ध्यान देने वाली तथ्य है कि सीपीएस परिवर्तन वैचारिक रूप से [[योनेडा एम्बेडिंग]] है।<ref>Mike Stay, [http://golem.ph.utexas.edu/category/2008/01/the_continuation_passing_trans.html "The Continuation Passing Transform and the Yoneda Embedding"]</ref> यह π-कैलकुलस में लैम्ब्डा कैलकुलस के एम्बेडिंग के समान है।<ref>Mike Stay, [http://golem.ph.utexas.edu/category/2009/09/the_pi_calculus_ii.html "The Pi Calculus II"]</ref><ref>{{cite CiteSeerX | first = Gérard | last = Boudol | citeseerx = 10.1.1.52.6034 | title = The π-Calculus in Direct Style | year = 1997 }}</ref>
==अन्य क्षेत्रों में उपयोग==
==अन्य क्षेत्रों में उपयोग==
[[कंप्यूटर विज्ञान|कंप्यूटर साइंस]] के बाहर, सरल अभिव्यक्तियों को सम्मिश्र अभिव्यक्तियों में लिखने की ट्रेडिशनल पद्धति के विकल्प के रूप में सीपीएस अधिक सामान्य रुचि है। उदाहरण के लिए, लिंगविस्टिक शब्दार्थ के अंतर्गत, [[क्रिस बार्कर (भाषाविद्)|क्रिस बार्कर]] और उनके सहयोगियों ने सुझाव दिया है कि सीपीएस का उपयोग करके वाक्यों के अर्थ निर्दिष्ट करने से [[प्राकृतिक भाषा|नेचुरल]] लैंग्वेज में कुछ घटनाओं की व्याख्या हो सकती है।<ref>{{Cite journal|last=Barker|first=Chris|date=2002-09-01|title=निरंतरता और परिमाणीकरण की प्रकृति|journal=Natural Language Semantics|language=en|volume=10|issue=3|pages=211–242|doi=10.1023/A:1022183511876|s2cid=118870676|issn=1572-865X|url=http://www.semanticsarchive.net/Archive/902ad5f7/barker.continuations.pdf}}</ref>
[[कंप्यूटर विज्ञान|कंप्यूटर साइंस]] के बाहर, सरल अभिव्यक्तियों को सम्मिश्र अभिव्यक्तियों में लिखने की ट्रेडिशनल पद्धति के विकल्प के रूप में सीपीएस अधिक सामान्य रुचि है। उदाहरण के लिए, लिंगविस्टिक शब्दार्थ के अंतर्गत, [[क्रिस बार्कर (भाषाविद्)|क्रिस बार्कर]] और उनके सहयोगियों ने सुझाव दिया है कि सीपीएस का उपयोग करके वाक्यों के अर्थ निर्दिष्ट करने से [[प्राकृतिक भाषा|नेचुरल]] लैंग्वेज में कुछ घटनाओं की व्याख्या हो सकती है।<ref>{{Cite journal|last=Barker|first=Chris|date=2002-09-01|title=निरंतरता और परिमाणीकरण की प्रकृति|journal=Natural Language Semantics|language=en|volume=10|issue=3|pages=211–242|doi=10.1023/A:1022183511876|s2cid=118870676|issn=1572-865X|url=http://www.semanticsarchive.net/Archive/902ad5f7/barker.continuations.pdf}}</ref>


गणित में, कंप्यूटर प्रोग्राम और गणितीय प्रमाणों के मध्य करी-हावर्ड समरूपता, निरंतरता-पासिंग शैली अनुवाद को [[अंतर्ज्ञानवादी तर्क|इंटीसनस्टिक]] लॉजिक में [[शास्त्रीय तर्क|मौलिक]] लॉजिक के दोहरे-ऋणात्मक [[एम्बेडिंग]] की विविधता से संबंधित करती है [[अंतर्ज्ञानवादी तर्क|इंटीसनस्टिक]] (रचनात्मक) लॉजिक। नियमित दोहरे-ऋणात्मक अनुवाद के विपरीत, जो परमाणु प्रस्तावों p को ((p → ⊥) → ⊥) में माप करता है, निरंतरता पासिंग शैली अंतिम अभिव्यक्ति के प्रकार से ⊥ को प्रतिस्थापित करती है। तदनुसार, उपरोक्त उदाहरण के अनुसार, सीपीएस अभिव्यक्ति की निरंतरता के रूप में पहचान फ़ंक्शन को पारित करके परिणाम प्राप्त किया जाता है।
गणित में, कंप्यूटर प्रोग्राम और गणितीय प्रमाणों के मध्य करी-हावर्ड समरूपता, निरंतर-अग्रगामी शैली अनुवाद को [[अंतर्ज्ञानवादी तर्क|इंटीसनस्टिक]] लॉजिक में [[शास्त्रीय तर्क|मौलिक]] लॉजिक के दोहरे-ऋणात्मक [[एम्बेडिंग]] की विविधता से संबंधित करती है [[अंतर्ज्ञानवादी तर्क|इंटीसनस्टिक]] (रचनात्मक) लॉजिक। नियमित दोहरे-ऋणात्मक अनुवाद के विपरीत, जो परमाणु प्रस्तावों p को ((p → ⊥) → ⊥) में माप करता है, निरंतर अग्रगामी शैली अंतिम अभिव्यक्ति के प्रकार से ⊥ को प्रतिस्थापित करती है। तदनुसार, उपरोक्त उदाहरण के अनुसार, सीपीएस अभिव्यक्ति की निरंतर के रूप में पहचान फ़ंक्शन को पारित करके परिणाम प्राप्त किया जाता है।


शास्त्रीय लॉजिक स्वयं प्रोग्राम की निरंतरता में सीधे हेरफेर करने से संबंधित है, जैसा कि स्कीम के कॉल-विथ-वर्तमान-निरंतरता नियंत्रण ऑपरेटर में, टिम ग्रिफिन (निकट से संबंधित सी नियंत्रण ऑपरेटर का उपयोग करके) के कारण अवलोकन है।<ref>{{cite book
शास्त्रीय लॉजिक स्वयं प्रोग्राम की निरंतर में सीधे हेरफेर करने से संबंधित है, जैसा कि स्कीम के कॉल-विथ-वर्तमान-निरंतर नियंत्रण ऑपरेटर में, टिम ग्रिफिन (निकट से संबंधित सी नियंत्रण ऑपरेटर का उपयोग करके) के कारण अवलोकन है।<ref>{{cite book
| first = Timothy | last = Griffin
| first = Timothy | last = Griffin
| title = Proceedings of the 17th ACM SIGPLAN-SIGACT symposium on Principles of programming languages - POPL '90
| title = Proceedings of the 17th ACM SIGPLAN-SIGACT symposium on Principles of programming languages - POPL '90
Line 246: Line 246:
==टिप्पणियाँ==
==टिप्पणियाँ==
{{Reflist}}
{{Reflist}}


==संदर्भ==
==संदर्भ==

Revision as of 18:21, 6 August 2023

फंक्शनल प्रोग्रामिंग में, निरंतर-अग्रगामी शैली (सीपीएस) प्रोग्रामिंग की शैली है जिसमें नियंत्रण प्रवाह को निरंतर के रूप में स्पष्ट रूप से पास्ड किया जाता है। इसकी तुलना प्रत्यक्ष शैली से की जाती है, जो की प्रोग्रामिंग की उसुअल शैली है। अतः गेराल्ड जे सुसमैन और गाइ एल. स्टील, जूनियर ने एआई मेमो 349 (1975) में वाक्यांश गढ़ा, जो स्कीम (प्रोग्रामिंग लैंग्वेज ) प्रोग्रामिंग लैंग्वेज का प्रथम वर्शन निर्धारित करता है।[1][2] इस प्रकार से जॉन सी. रेनॉल्ड्स निरंतर की अनेक खोजों का विस्तृत अकाउंट देते हैं।[3]

निरंतर-अग्रगामी शैली में लिखा गया फ़ंक्शन एक्सप्लिसिट लॉजिक लेता है: स्पष्ट "निरंतर"; अर्थात , लॉजिक का कार्य: और स्पष्ट निरंतर; अर्थात लॉजिक का कार्य है। जब सीपीएस फ़ंक्शन ने अपने परिणाम मान की गणना की है, तो यह लॉजिक के रूप में इस मान के साथ निरंतर फ़ंक्शन को कॉल करके इसे वापस कर देता है। इसका अर्थ यह है कि सीपीएस फ़ंक्शन को प्रयुक्त करते समय, कॉलिंग फ़ंक्शन को सबरूटीन के रिटर्न वैल्यू के साथ प्रयुक्त करने के लिए प्रोसीजर प्रदान करने की आवश्यकता होती है। अतः कोड को इस रूप में व्यक्त करने से अनेक वस्तु स्पष्ट हो जाती हैं जो की प्रत्यक्ष शैली में अंतर्निहित होती हैं। इनमें सम्मिलित हैं: इस प्रकार से प्रोसीजर रिटर्न, जो निरंतर के लिए कॉल के रूप में स्पष्ट हो जाते हैं; इंटरमीडिएट मान, जो सभी दिए गए नाम हैं; लॉजिक इवैल्यूएशन का क्रम, जिसे स्पष्ट किया गया है; और टेल कॉल , जो बस उसी निरंतर के साथ प्रोसीजर को कॉल करते हैं, जो उनमोडीफ़िएड, कॉलर को दी गई थी।

प्रोग्राम को स्वचालित रूप से डायरेक्ट स्टाइल से सीपीएस में परिवर्तन किया जा सकता है। और फंक्शनल और लॉजिक प्रोग्रामिंग कंपाइलर प्रायः सीपीएस को इंटरमीडिएट रिप्रजेंटेशन के रूप में उपयोग करते हैं जहां इम्पेरेटिव प्रोग्रामिंग या प्रोसीज़रल प्रोग्रामिंग लैंग्वेज के लिए कंपाइलर ए असाइनमेंट फॉर्म (एसएसए) का उपयोग किया जाता है।[4] इस प्रकार से एसएसए औपचारिक रूप से सीपीएस के सबसेट के समान है (नॉन-लोकल कण्ट्रोल फ्लो को छोड़कर, जो तब नहीं होता है जब सीपीएस को इंटरमीडिएट रिप्रजेंटेशन के रूप में उपयोग किया जाता है)।[5] इस प्रकार से फंक्शनल कंपाइलर सीपीएस में 'थंक (विलंबित गणना)' (नीचे दिए गए उदाहरणों में वर्णित) के अतिरिक्त ए-नार्मल फॉर्म (एएनएफ) (किन्तु केवल उत्सुक इवैल्यूएशन की आवश्यकता वाली लैंग्वेज के लिए) का उपयोग कर सकते हैं। अतः सीपीएस का उपयोग स्थानीय या ग्लोबल शैली के रूप में प्रोग्रामर की तुलना में कंपाइलरों द्वारा अधिक बार किया जाता है।

उदाहरण

इस प्रकार से सीपीएस में, प्रत्येक प्रोसीजर एक्स्ट्रा लॉजिक प्राप्त करती है जो यह दर्शाती है कि फ़ंक्शन द्वारा गणना किए जा रहे परिणाम के साथ क्या किया जाना चाहिए। यह, सामान्यतः उपलब्ध विभिन्न प्रकार के निर्माणों को प्रतिबंधित करने वाली रेस्ट्रिक्टिव शैली के साथ, प्रोग्राम के शब्दार्थ को उजागर करने के लिए उपयोग किया जाता है, जिससे उनका विश्लेषण करना सरल हो जाता है। यह शैली असामान्य नियंत्रण स्ट्रूकवेरिएबल को जैसे कैच/थ्रो या नियंत्रण के अन्य नॉन-लोकल ट्रांस्फर्स व्यक्त करना भी सरल बनाती है।

अतः सीपीएस की कुंजी यह याद रखना है कि (a) प्रत्येक फ़ंक्शन एक्स्ट्रा लॉजिक लेता है जिसे इसकी निरंतर के रूप में जाना जाता है, और (b) फ़ंक्शन कॉल में प्रत्येक लॉजिक या तो वेरिएबल या लैम्ब्डा (प्रोग्रामिंग) होना चाहिए (अधिक सम्मिश्र अभिव्यक्ति नहीं)। इसमें अभिव्यक्ति को इनसाइड-आउट करने का प्रभाव होता है क्योंकि अभिव्यक्ति के सबसे इनरमोस्ट पार्ट्स का इवैल्यूएशन पहले किया जाना चाहिए, चूंकि इस प्रकार सीपीएस इवैल्यूएशन के क्रम के साथ-साथ नियंत्रण प्रवाह को भी स्पष्ट करता है। प्रत्यक्ष शैली में कोड और संबंधित सीपीएस के कुछ उदाहरण नीचे दिखाई देते हैं। ये उदाहरण योजना (प्रोग्रामिंग लैंग्वेज) में लिखे गए हैं; प्रिमिटीव्स के अनुसार निरंतर फ़ंक्शन k: को नामित पैरामीटर के रूप में दर्शाया जाता है

Direct style
Continuation passing style
(define (pyth x y)
 (sqrt (+ (* x x) (* y y))))
(define (pyth& x y k)
 (*& x x (lambda (x2)
          (*& y y (lambda (y2)
                   (+& x2 y2 (lambda (x2py2)
                              (sqrt& x2py2 k))))))))
(define (factorial n)
 (if (= n 0)
     1     ; NOT tail-recursive
     (* n (factorial (- n 1)))))
(define (factorial& n k)
 (=& n 0 (lambda (b)
          (if b                    ; growing continuation
              (k 1)                ; in the recursive call
              (-& n 1 (lambda (nm1)
                       (factorial& nm1 (lambda (f)
                                        (*& n f k)))))))))
(define (factorial n)
 (f-aux n 1))
(define (f-aux n a)
 (if (= n 0)
     a        ; tail-recursive
     (f-aux (- n 1) (* n a))))
(define (factorial& n k) (f-aux& n 1 k))
(define (f-aux& n a k)
 (=& n 0 (lambda (b)
          (if b                    ; unmodified continuation
              (k a)                ; in the recursive call
              (-& n 1 (lambda (nm1) 
                       (*& n a (lambda (nta)
                                (f-aux& nm1 nta k)))))))))

ध्यान दें कि सीपीएस वर्शन में, प्रिमिटीव्स का उपयोग किया जाता है, जैसे +& और *& स्वयं सीपीएस हैं, प्रत्यक्ष शैली नहीं है, इसलिए उपरोक्त उदाहरणों को स्कीम सिस्टम में कार्य करने के लिए हमें प्रिमिटीव्स के इन सीपीएस वर्शन को लिखने की आवश्यकता होती है, उदाहरण के लिए *& द्वारा परिभाषित:

(define (*& x y k)
 (k (* x y)))

सामान्य रूप से ऐसा करने के लिए, हम कन्वर्शन रूटीन लिख सकते हैं:

(define (cps-prim f)
 (lambda args
  (let ((r (reverse args)))
   ((car r) (apply f
             (reverse (cdr r)))))))
(define *& (cps-prim *))
(define +& (cps-prim +))

इस प्रकार से सीपीएस में लिखी गई प्रोसीजर को प्रत्यक्ष शैली में लिखी गई प्रोसीजर से कॉल करने के लिए, निरंतर प्रदान करना आवश्यक है जो की सीपीएस प्रोसीजर द्वारा गणना किए गए परिणाम प्राप्त करती है। अतः उपरोक्त उदाहरण में (यह मानते हुए कि सीपीएस प्राइमेटिव्स प्रदान किए गए हैं), हम कॉल कर सकते हैं (factorial& 10 (lambda (x) (display x) (newline))).

अतः सीपीएस में प्रिमिटीव्स कार्य प्रदान करने के विधि में कंपाइलरों के मध्य कुछ विविधता है। ऊपर हमने सबसे सिम्प्लेस्ट कन्वेंशन का उपयोग किया है, चूंकि कभी-कभी बूलियन प्राइमेटिव प्रदान किए जाते हैं जो दो संभावित स्तिथियों में कॉल करने के लिए दो थंक (विलंबित गणना) लेते हैं, इसलिए (=& n 0 (lambda (b) (if b ...))) अंदर कॉल करें f-aux& उपरोक्त परिभाषा के स्थान पर इस प्रकार कॉन्टीनुएशन (=& n 0 (lambda () (k a)) (lambda () (-& n 1 ...))). लिखा जाएगा इसी तरह, कभी-कभी if प्रिमिटिव स्वयं सीपीएस में सम्मिलित नहीं है, किन्तु फ़ंक्शन if& है प्रदान किया जाता है जिसमें तीन लॉजिक होते हैं: बूलियन स्थिति और सशर्त की दो आर्म्स के अनुरूप दो थंक आदि।

ऊपर दिखाए गए अनुवाद दर्शाया गया हैं कि सीपीएस ग्लोबल परिवर्तन है। जैसी कि अपेक्षा की जा सकती है, प्रत्यक्ष शैली का फैक्टोरियल ही लॉजिक प्राप्त करता है; इस प्रकार से लॉजिक और निरंतर सीपीएस फैक्टोरियल टू प्राप्त करता है: अतः सीपीएस-एड फ़ंक्शन को कॉल करने वाले किसी भी फ़ंक्शन को या तो नई निरंतर प्रदान करनी होगी या अपना स्वयं का पास करना होगा; सीपीएस-एड फ़ंक्शन से नॉन-सीपीएस फ़ंक्शन में कोई भी कॉल अंतर्निहित निरंतर का उपयोग करती है। इस प्रकार, फ़ंक्शन स्टैक की पूर्ण अनुपस्थिति सुनिश्चित करने के लिए, एंटीरे प्रोग्राम सीपीएस में होना चाहिए।

हास्केल में सीपीएस (प्रोग्रामिंग लैंग्वेज)

इस अनुभाग में हम फ़ंक्शन लिखेंगे pyth जो पाइथागोरस प्रमेय का उपयोग करके कर्ण की गणना करता है। और pyth ट्रेडिशनल इम्प्लीमेंटेशन फ़ंक्शन इस तरह दिखता है:

pow2 :: Float -> Float
pow2 x = x ** 2

add :: Float -> Float -> Float
add x y = x + y

pyth :: Float -> Float -> Float
pyth x y = sqrt (add (pow2 x) (pow2 y))

ट्रेडिशनल फ़ंक्शन को सीपीएस में परिवर्तन के लिए, हमें इसके सिग्नेवेरिएबल को परिवर्तन की आवश्यकता है। फ़ंक्शन को फ़ंक्शन प्रकार का और लॉजिक प्राप्त होगा, और इसका रिटर्न प्रकार उस फ़ंक्शन पर निर्भर करता है:

pow2' :: Float -> (Float -> a) -> a
pow2' x cont = cont (x ** 2)

add' :: Float -> Float -> (Float -> a) -> a
add' x y cont = cont (x + y)

-- Types a -> (b -> c) and a -> b -> c are equivalent, so CPS function
-- may be viewed as a higher order function
sqrt' :: Float -> ((Float -> a) -> a)
sqrt' x = \cont -> cont (sqrt x)

pyth' :: Float -> Float -> (Float -> a) -> a
pyth' x y cont = pow2' x (\x2 -> pow2' y (\y2 -> add' x2 y2 (\anb -> sqrt' anb cont)))

सर्वप्रथम हम pyth' फ़ंक्शन में a के वर्ग की गणना करते हैं और लैम्ब्डा फ़ंक्शन को निरंतर के रूप में पास करते हैं जो प्रथम लॉजिक के रूप में a के वर्ग को स्वीकार करेगा। और इसी तरह जब तक हम अपनी गणना के परिणाम तक नहीं पहुंच जाते, इस फ़ंक्शन का परिणाम प्राप्त करने के लिए हम id फ़ंक्शन को अंतिम लॉजिक के रूप में पास कर सकते हैं, जो उसे दिए गए मान pyth' 3 4 id == 5.0 को अपरिवर्तित रिटर्निंग करता है:

एमटीएल लाइब्रेरी, जिसे ग्लासगो हास्केल कंपाइलर के साथ भेजा जाता है, में Control.Monad.Cont. मॉड्यूल है यह मॉड्यूल कॉन्ट प्रकार प्रदान करता है, जो मोनाड और कुछ अन्य उपयोगी कार्यों को प्रयुक्त करता है। निम्नलिखित स्निपेट कंट का उपयोग करके pyth' ' फ़ंक्शन दिखाता है:

pow2_m :: Float -> Cont a Float
pow2_m a = return (a ** 2)

pyth_m :: Float -> Float -> Cont a Float
pyth_m a b = do
  a2 <- pow2_m a
  b2 <- pow2_m b
  anb <- cont (add' a2 b2)
  r <- cont (sqrt' anb)
  return r

इस प्रकार से न केवल सिंटैक्स क्लीनर है, किन्तु यह प्रकार हमें MonadCont m => ((a -> m b) -> m a) -> m a. प्रकार के साथ फ़ंक्शन callCC का उपयोग करने की अनुमति देता है। इस फ़ंक्शन में फ़ंक्शन प्रकार का लॉजिक होता है; वह फ़ंक्शन लॉजिक फ़ंक्शन को भी स्वीकार करता है, जो उसके कॉल के पश्चात होने वाली सभी गणनाओं को छोड़ देता है। उदाहरण के लिए, आइए pyth फ़ंक्शन के निष्पादन को अंत कर दें यदि इसका कम से कम लॉजिक ऋणात्मक है और शून्य रिटर्निंग कर रहा है:

pyth_m :: Float -> Float -> Cont a Float
pyth_m a b = callCC $ \exitF -> do -- $ sign helps to avoid parentheses: a $ b + c == a (b + c)
  when (b < 0 || a < 0) (exitF 0.0) -- when :: Applicative f => Bool -> f () -> f ()
  a2 <- pow2_m a
  b2 <- pow2_m b
  anb <- cont (add' a2 b2)
  r <- cont (sqrt' anb)
  return r


ऑब्जेक्टस के रूप में निरंतर

निरंतर के साथ प्रोग्रामिंग तब भी उपयोगी हो सकती है जब कोई कॉल करने वाला कॉल पूरा होने तक वेट नहीं करना चाहता है। इस प्रकार से उदाहरण के लिए, यूजर-इंटरफ़ेस (यूआई) प्रोग्रामिंग में, रूटीन डायलॉग बॉक्स फ़ील्ड सेट कर सकता है और इन्हें निरंतर फ़ंक्शन के साथ यूआई फ्रेमवर्क में पास कर सकता है। यह कॉल तुरंत रिटर्न आती है, जिससे एप्लिकेशन कोड तब तक निरंतर रहता है जब तक उपयोगकर्ता डायलॉग बॉक्स के साथ इंटरैक्ट करता है। बार जब उपयोगकर्ता "ओके" बटन दबाता है, तो फ्रेमवर्क अपडेटेड फ़ील्ड के साथ निरंतर फ़ंक्शन को कॉल करता है। चूंकि कोडिंग की यह शैली निरंतर का उपयोग करती है, यह पूर्ण सीपीएस नहीं है।

function confirmName() {
    fields.name = name;
    framework.Show_dialog_box(fields, confirmNameContinuation);
}

function confirmNameContinuation(fields) {
    name = fields.name;
}

समान विचार का उपयोग तब किया जा सकता है जब फ़ंक्शन को किसी डिफरेंट थ्रेड में या किसी डिफरेंट प्रोसेसर पर चलाना होता है। फ्रेमवर्क वर्कर थ्रेड में कॉल किए गए फ़ंक्शन को निष्पादित कर सकता है, फिर वर्कर के परिणामों के साथ मूल थ्रेड में निरंतर फ़ंक्शन को कॉल कर सकता है। यह जावा 8 (प्रोग्रामिंग लैंग्वेज) में स्विंग (जावा) यूआई फ्रेमवर्क का उपयोग कर रहा है:

void buttonHandler() {
    // This is executing in the Swing UI thread.
    // We can access UI widgets here to get query parameters.
    int parameter = getField();

    new Thread(() => {
        // This code runs in a separate thread.
        // We can do things like access a database or a 
        // blocking resource like the network to get data.
        int result = lookup(parameter);

        javax.swing.SwingUtilities.invokeLater(() => {
            // This code runs in the UI thread and can use
            // the fetched data to fill in UI widgets.
            setField(result);
        });
    }).start();
}


टेल कॉल

सीपीएस में प्रत्येक कॉल टेल कॉल है, और निरंतर स्पष्ट रूप से पारित की जाती है। टेल कॉल अनुकूलन (टीसीओ) के बिना सीपीएस का उपयोग करने से रिकर्सन के समय न केवल निर्मित निरंतर संभावित रूप से बढ़ेगी, किन्तु कॉल स्टैक भी बढ़ता है। यह सामान्यतः अनिष्ट है, किन्तु इसका उपयोग (योजना इम्प्लीमेंटेशन ) या चिकन स्कीम कंपाइलर अर्थात रोचक विधियों से किया गया है। चूंकि सीपीएस और टीसीओ अंतर्निहित फ़ंक्शन रिटर्न की अवधारणा को समाप्त करते हैं, उनका संयुक्त उपयोग रन-टाइम स्टैक की आवश्यकता को समाप्त कर सकता है। अतः फंक्शनल प्रोग्रामिंग लैंग्वेज के लिए अनेक कंपाइलर और इनटरप्रेटर्शिप नए विधियों से इस क्षमता का उपयोग करते हैं।[6]

उपयोग और इम्प्लीमेंटेशन

निरंतर अग्रगामी शैली का उपयोग फंक्शनल लैंग्वेज में निरंतर को प्रयुक्त करने और प्रवाह ऑपरेटरों को नियंत्रित करने के लिए किया जा सकता है जिसमें प्रथम श्रेणी की निरंतर की सुविधा नहीं है किन्तु प्रथम श्रेणी के फ़ंक्शन और टेल-कॉल अनुकूलन हैं। टेल-कॉल ऑप्टिमाइज़ेशन के बिना, ट्रैम्पोलिन (कंप्यूटर) जैसी तकनीकों का उपयोग किया जा सकता है, अर्थात लूप का उपयोग करना जो पुनरावृत्त रूप से थंक ( फंक्शनल प्रोग्रामिंग)-रिटर्निंग फ़ंक्शंस को आमंत्रित करता है; प्रथम श्रेणी के फ़ंक्शंस के बिना, ऐसे लूप में टेल कॉल को केवल गोटो में परिवर्तित करना भी संभव है।

इस प्रकार से सीपीएस में कोड लिखना, चूंकि असंभव नहीं है, प्रायः एरर-प्रोन होता है। विभिन्न अनुवाद हैं, जिन्हें सामान्यतः शुद्ध लैम्ब्डा कैलकुलस के या दो-पास रूपांतरण के रूप में परिभाषित किया जाता है, जो प्रत्यक्ष शैली अभिव्यक्तियों को सीपीएस अभिव्यक्तियों में परिवर्तित करता है। चूंकि , ट्रम्पोलिन्ड शैली में लिखना अत्यंत कठिन है; जब उपयोग किया जाता है, तो यह सामान्यतः किसी प्रकार के परिवर्तन का लक्ष्य होता है, जैसे कि कंपाइलर आदि।

एक से अधिक निरंतर का उपयोग करने वाले कार्यों को विभिन्न नियंत्रण प्रवाह प्रतिमानों को कैप्वेरिएबल के लिए परिभाषित किया जा सकता है, उदाहरण के लिए (स्कीम (प्रोग्रामिंग लैंग्वेज) में) है:

(define (/& x y ok err)
 (=& y 0.0 (lambda (b)
            (if b
                (err (list "div by zero!" x y))
                (ok (/ x y))))))

यह ध्यान देने वाली तथ्य है कि सीपीएस परिवर्तन वैचारिक रूप से योनेडा एम्बेडिंग है।[7] यह π-कैलकुलस में लैम्ब्डा कैलकुलस के एम्बेडिंग के समान है।[8][9]

अन्य क्षेत्रों में उपयोग

कंप्यूटर साइंस के बाहर, सरल अभिव्यक्तियों को सम्मिश्र अभिव्यक्तियों में लिखने की ट्रेडिशनल पद्धति के विकल्प के रूप में सीपीएस अधिक सामान्य रुचि है। उदाहरण के लिए, लिंगविस्टिक शब्दार्थ के अंतर्गत, क्रिस बार्कर और उनके सहयोगियों ने सुझाव दिया है कि सीपीएस का उपयोग करके वाक्यों के अर्थ निर्दिष्ट करने से नेचुरल लैंग्वेज में कुछ घटनाओं की व्याख्या हो सकती है।[10]

गणित में, कंप्यूटर प्रोग्राम और गणितीय प्रमाणों के मध्य करी-हावर्ड समरूपता, निरंतर-अग्रगामी शैली अनुवाद को इंटीसनस्टिक लॉजिक में मौलिक लॉजिक के दोहरे-ऋणात्मक एम्बेडिंग की विविधता से संबंधित करती है इंटीसनस्टिक (रचनात्मक) लॉजिक। नियमित दोहरे-ऋणात्मक अनुवाद के विपरीत, जो परमाणु प्रस्तावों p को ((p → ⊥) → ⊥) में माप करता है, निरंतर अग्रगामी शैली अंतिम अभिव्यक्ति के प्रकार से ⊥ को प्रतिस्थापित करती है। तदनुसार, उपरोक्त उदाहरण के अनुसार, सीपीएस अभिव्यक्ति की निरंतर के रूप में पहचान फ़ंक्शन को पारित करके परिणाम प्राप्त किया जाता है।

शास्त्रीय लॉजिक स्वयं प्रोग्राम की निरंतर में सीधे हेरफेर करने से संबंधित है, जैसा कि स्कीम के कॉल-विथ-वर्तमान-निरंतर नियंत्रण ऑपरेटर में, टिम ग्रिफिन (निकट से संबंधित सी नियंत्रण ऑपरेटर का उपयोग करके) के कारण अवलोकन है।[11]

यह भी देखें

  • टेल प्रत्यावर्तन या ट्रैम्पोलिनिंग के माध्यम से

टिप्पणियाँ

  1. Sussman, Gerald Jay; Steele, Guy L., Jr. (December 1975). "Scheme: An interpreter for extended lambda calculus" . AI Memo. 349: 19. That is, in this continuation-passing programming style, a function always "returns" its result by "sending" it to another function. This is the key idea.{{cite journal}}: CS1 maint: multiple names: authors list (link)
  2. Sussman, Gerald Jay; Steele, Guy L., Jr. (December 1998). "Scheme: A Interpreter for Extended Lambda Calculus" (reprint). Higher-Order and Symbolic Computation. 11 (4): 405–439. doi:10.1023/A:1010035624696. S2CID 18040106. We believe that this was the first occurrence of the term "continuation-passing style" in the literature. It has turned out to be an important concept in source code analysis and transformation for compilers and other metaprogramming tools. It has also inspired a set of other "styles" of program expression.{{cite journal}}: CS1 maint: multiple names: authors list (link)
  3. Reynolds, John C. (1993). "The Discoveries of Continuations". LISP and Symbolic Computation. 6 (3–4): 233–248. CiteSeerX 10.1.1.135.4705. doi:10.1007/bf01019459. S2CID 192862.
  4. *Appel, Andrew W. (April 1998). "SSA is Functional Programming". ACM SIGPLAN Notices. 33 (4): 17–20. CiteSeerX 10.1.1.34.3282. doi:10.1145/278283.278285. S2CID 207227209.
  5. *Kelsey, Richard A. (March 1995). "A Correspondence between Continuation Passing Style and Static Single Assignment Form". ACM SIGPLAN Notices. 30 (3): 13–22. CiteSeerX 10.1.1.489.930. doi:10.1145/202530.202532.
  6. Appel, Andrew W. (1992). Compiling with Continuations. Cambridge University Press. ISBN 0-521-41695-7.
  7. Mike Stay, "The Continuation Passing Transform and the Yoneda Embedding"
  8. Mike Stay, "The Pi Calculus II"
  9. Boudol, Gérard (1997). "The π-Calculus in Direct Style". CiteSeerX 10.1.1.52.6034.
  10. Barker, Chris (2002-09-01). "निरंतरता और परिमाणीकरण की प्रकृति" (PDF). Natural Language Semantics (in English). 10 (3): 211–242. doi:10.1023/A:1022183511876. ISSN 1572-865X. S2CID 118870676.
  11. Griffin, Timothy (January 1990). "A formulae-as-type notion of control". Proceedings of the 17th ACM SIGPLAN-SIGACT symposium on Principles of programming languages - POPL '90. pp. 47–58. doi:10.1145/96709.96714. ISBN 978-0897913430. S2CID 3005134. {{cite book}}: |journal= ignored (help)

संदर्भ