प्रक्रियात्मक पैरामीटर: Difference between revisions

From Vigyanwiki
No edit summary
No edit summary
 
(13 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[ कम्प्यूटिंग |कम्प्यूटिंग]] में, एक प्रक्रियात्मक पैरामीटर एक प्रक्रिया का एक [[पैरामीटर (कंप्यूटर विज्ञान)|पैरामीटर]] होता है जो स्वयं एक प्रक्रिया होती है।
[[ कम्प्यूटिंग |कम्प्यूटिंग]] में, '''प्रक्रियात्मक पैरामीटर''' प्रक्रिया का एक [[पैरामीटर (कंप्यूटर विज्ञान)|पैरामीटर]] होता है जो स्वयं एक प्रक्रिया होती है।


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


यह उपकरण उन लैंग्वेज में विशेष रूप से प्रभावी और सुविधाजनक है जो लोकल फ़ंक्शन परिभाषाओं जैसे पास्कल और C की आधुनिक जीएनयू लैंग्वेज का समर्थन करते हैं। यह तब और भी अधिक होता है जब फ़ंक्शन क्लोजर उपलब्ध होते हैं। [[ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग]] लैंग्वेज में ऑब्जेक्ट द्वारा समान कार्यक्षमता (और अधिक) लेकिन काफी अधिक कीमत पर प्रदान की जाती है।
यह उपकरण उन लैंग्वेज में विशेष रूप से प्रभावी और सुविधाजनक है जो लोकल फ़ंक्शन परिभाषाओं जैसे पास्कल और C की आधुनिक जीएनयू लैंग्वेज का समर्थन करते हैं। यह तब और भी अधिक होता है जब फ़ंक्शन क्लोजर उपलब्ध होते हैं। [[ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग]] लैंग्वेज में ऑब्जेक्ट द्वारा समान कार्यक्षमता (और अधिक) लेकिन काफी अधिक कीमत पर प्रदान की जाती है।


प्रक्रियात्मक पैरामीटर कुछ हद तक प्रथम श्रेणी फ़ंक्शन और एनोनिमस फ़ंक्शन की अवधारणाओं से संबंधित हैं, लेकिन उनसे अलग हैं। इन दोनों अवधारणाओं का संबंध इस बात से अधिक है कि कार्यों को कैसे परिभाषित किया जाता है, न कि उनका उपयोग कैसे किया जाता है।
प्रक्रियात्मक पैरामीटर कुछ हद तक प्रथम श्रेणी फ़ंक्शन और एनोनिमस फ़ंक्शन की अवधारणाओं से संबंधित हैं, लेकिन उनसे अलग हैं। इन दोनों अवधारणाओं का संबंध इस बात से अधिक है कि फ़ंक्शन को कैसे परिभाषित किया जाता है, न कि उनका उपयोग कैसे किया जाता है।


==बुनियादी अवधारणा==
==मूल अवधारणा==
अधिकांश लैंग्वेज में जो यह सुविधा प्रदान करती हैं, सबरूटीन पी के एक प्रक्रियात्मक पैरामीटर एफ को पी के शरीर के अंदर बुलाया जा सकता है जैसे कि यह एक सामान्य प्रक्रिया थी:
यह सुविधा प्रदान करने वाली अधिकांश लैंग्वेज में, सबरूटीन ''P'' के एक प्रक्रियात्मक पैरामीटर ''f'' को ''P'' के बॉडी के अंदर कॉल किया जा सकता है जैसे कि यह एक सामान्य प्रक्रिया थी:<syntaxhighlight lang="pas">
 
procedure P(f):
'प्रक्रिया' पी(एफ):
    return f(6,3) * f(2,1)
    'वापसी' f(6,3) * f(2,1)
</syntaxhighlight>सबरूटीन ''P'' को कॉल करते समय, किसी को इसे एक तर्क देना होगा, जो कि ''P'' द्वारा अपने पैरामीटर ''f'' का उपयोग करने के तरीके के साथ संगत कुछ पहले से परिभाषित फ़ंक्शन होना चाहिए। उदाहरण के लिए, यदि हम परिभाषित करते हैं।<syntaxhighlight lang="pascal">
 
procedure plus(x, y):
सबरूटीन पी को कॉल करते समय, किसी को इसे एक तर्क देना होगा, वह कुछ पहले से परिभाषित फ़ंक्शन होना चाहिए जो पी अपने पैरामीटर एफ का उपयोग करने के तरीके के साथ संगत हो। उदाहरण के लिए, यदि हम परिभाषित करें
    return x + y
 
</syntaxhighlight>तो हम ''P'' (''plus'') कह सकते हैं, और परिणाम ''plus''(6,3) * ''plus''(2,1) = (6 + 3)*(2 + 1) = 27 होगा। दूसरी ओर, यदि हम परिभाषित करते हैं।<syntaxhighlight lang="pascal">
'प्रक्रिया' प्लस(x, y):
procedure quot(u, v):
    'वापसी' x + y
    return u/v
 
</syntaxhighlight>फिर ''P'' (''quot'') को कॉल करने पर ''quot''(6,3)*''quot''(2,1) = (6/3)*(2/1) = 4 आएगा। अंत में, यदि हम परिभाषित करते हैं<syntaxhighlight lang="pascal">
तब हम P (प्लस) कह सकते हैं, और परिणाम प्लस(6,3) * प्लस(2,1) = (6 + 3)*(2 + 1) = 27 होगा। दूसरी ओर, यदि हम परिभाषित करते हैं
procedure evil(z)
 
    return z + 100
'प्रक्रिया' quot(u, v):
</syntaxhighlight>तब कॉल ''P'' (''evil'') का कोई विशेष अर्थ नहीं होगा, और इसे एक त्रुटि के रूप में चिह्नित किया जा सकता है।
    'वापसी' यू/वी
 
फिर कॉल P (quot) quot(6,3)*quot(2,1) = (6/3)*(2/1) = 4 लौटाएगा। अंत में, यदि हम परिभाषित करते हैं
 
'प्रक्रिया' बुराई(z)
    'वापसी' z + 100
 
तब कॉल पी (बुराई) का कोई खास मतलब नहीं होगा, और इसे एक त्रुटि के रूप में चिह्नित किया जा सकता है।


===वाक्यविन्यास विवरण===
===वाक्यविन्यास विवरण===
कुछ प्रोग्रामिंग भाषाएं जिनमें यह सुविधा है, वे प्रत्येक प्रक्रियात्मक पैरामीटर एफ के लिए पूर्ण प्रकार की घोषणा की अनुमति दे सकती हैं या इसकी आवश्यकता हो सकती है, जिसमें इसके तर्कों की संख्या और प्रकार, और इसके परिणाम का प्रकार, यदि कोई हो, शामिल है। उदाहरण के लिए, C प्रोग्रामिंग भाषा में उपरोक्त उदाहरण को इस प्रकार लिखा जा सकता है
कुछ प्रोग्रामिंग भाषाएं जिनमें यह सुविधा है, वे प्रत्येक प्रक्रियात्मक पैरामीटर ''f'' के लिए एक पूर्ण प्रकार की घोषणा की अनुमति दे सकती हैं या इसकी आवश्यकता हो सकती है, जिसमें इसके तर्कों की संख्या और प्रकार और इसके परिणाम का प्रकार, यदि कोई हो, सम्मिलित है। उदाहरण के लिए, C प्रोग्रामिंग लैंग्वेज में, ऊपर दिए गए उदाहरण को इस प्रकार लिखा जा सकता है
<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
int P(int (*f)(int a, int b)) {
int P(int (*f)(int a, int b)) {
Line 37: Line 29:
}
}
</syntaxhighlight>
</syntaxhighlight>
सिद्धांत रूप में, जब P को कॉल किया जाता है तो तर्क के रूप में पारित किया जाने वाला वास्तविक फ़ंक्शन actf प्रक्रिया पैरामीटर f के घोषित प्रकार के साथ टाइप-संगत होना चाहिए। इसका आमतौर पर मतलब यह है कि actf और f को एक ही प्रकार का परिणाम देना चाहिए, समान संख्या में तर्क होने चाहिए, और संबंधित तर्कों का प्रकार भी समान होना चाहिए। हालाँकि, तर्कों के नाम समान होने की आवश्यकता नहीं है, जैसा कि ऊपर प्लस और उद्धरण उदाहरणों द्वारा दिखाया गया है। हालाँकि, कुछ प्रोग्रामिंग भाषाएँ इस संबंध में अधिक प्रतिबंधात्मक या अधिक उदार हो सकती हैं।
सिद्धांत रूप में, वास्तविक फ़ंक्शन ''actf''  जिसे ''P'' को कॉल करने पर तर्क के रूप में पारित किया जाता है, प्रक्रिया पैरामीटर ''f''  के घोषित प्रकार के साथ टाइप-संगत होना चाहिए। इसका सामान्यतः मतलब यह है कि ''actf'' और ''f'' को एक ही प्रकार का परिणाम देना चाहिए, समान संख्या में तर्क होने चाहिए, और संबंधित तर्कों का प्रकार भी समान होना चाहिए। हालाँकि, तर्कों के नाम समान होने की आवश्यकता नहीं है, जैसा कि ऊपर दिए गए प्लस और उद्धरण उदाहरणों से एड्रेस चलता है। हालाँकि, इस संबंध में कुछ प्रोग्रामिंग भाषाएँ अधिक प्रतिबंधात्मक या अधिक उदार हो सकती हैं।


===स्कोपिंग===
===स्कोपिंग===
उन लैंग्वेज में जो प्रक्रियात्मक मापदंडों की अनुमति देते हैं, स्कोपिंग नियमों को आमतौर पर इस तरह से परिभाषित किया जाता है कि प्रक्रियात्मक मापदंडों को उनके मूल दायरे में निष्पादित किया जाता है। अधिक सटीक रूप से, मान लीजिए कि फ़ंक्शन actf को P के तर्क के रूप में, इसके प्रक्रियात्मक पैरामीटर f के रूप में पारित किया जाता है; और फिर पी के शरीर के अंदर से एफ को बुलाया जाता है। जबकि एक्टएफ निष्पादित किया जा रहा है, यह इसकी परिभाषा के वातावरण को देखता है।{{Example needed|date=December 2018}}
ऐसी लैंग्वेज में जो प्रक्रियात्मक पैरामीटर की अनुमति देती हैं, स्कोपिंग नियमों को सामान्यतः इस तरह से परिभाषित किया जाता है कि प्रक्रियात्मक पैरामीटर उनके मूल दायरे में निष्पादित होते हैं। अधिक सटीक रूप से, मान लीजिए कि फ़ंक्शन ''actf'' को पी के तर्क के रूप में, इसके प्रक्रियात्मक पैरामीटर ''f'' के रूप में पारित किया जाता है; और फिर ''P'' के बॉडी के अंदर से ''f'' कॉल किया जाता है जबकि ''actf'' निष्पादित किया जा रहा है, यह इसकी परिभाषा के वातावरण को देखता है।


इन दायरे नियमों का कार्यान्वयन मामूली नहीं है। जब तक actf अंततः निष्पादित हो जाता है, तब तक कॉल स्टैक#स्ट्रक्चर, जहां इसके पर्यावरण चर रहते हैं, स्टैक में मनमाने ढंग से गहरे हो सकते हैं। यह तथाकथित फनर्ग समस्या#डाउनवर्ड्स फनर्ग समस्या है।
इन दायरे नियमों का कार्यान्वयन साधारण नहीं है। जब तक ''actf'' अंततः निष्पादित होता है, तब तक सक्रियण रिकॉर्ड जहां इसके पर्यावरण चर रहते हैं, स्टैक में अनियमित ढंग से गहरे हो सकते हैं। यह तथाकथित डाउनवर्ड फ़नर्ग समस्या है।


==उदाहरण: सामान्य प्रविष्टि प्रकार==
==उदाहरण: जेनेरिक इंसर्शन सॉर्ट==
प्रक्रियात्मक पैरामीटर की अवधारणा को उदाहरणों द्वारा सबसे अच्छी तरह समझाया गया है। एक विशिष्ट अनुप्रयोग [[सम्मिलन सॉर्ट]] एल्गोरिदम का निम्नलिखित सामान्य कार्यान्वयन है, जो दो पूर्णांक पैरामीटर , बी और दो प्रक्रियात्मक पैरामीटर प्रीक, स्वैप लेता है:
प्रक्रियात्मक पैरामीटर की अवधारणा को उदाहरणों द्वारा सर्वोत्तम रूप से समझाया गया है। एक विशिष्ट एप्लिकेशन इंसर्शन सॉर्ट एल्गोरिदम का निम्नलिखित सामान्य कार्यान्वयन है, जो दो पूर्णांक पैरामीटर ''a'', ''b'' और दो प्रक्रियात्मक पैरामीटर prec, स्वैप लेता है:<syntaxhighlight lang="pascal">
procedure isort(a, b, prec, swap):
    integer i, j;
    i ← a;
    while i ≤ b do
        j ← i;
        while j > a and prec(j, j−1) do
            swap(j, j−1);
            j ← j−1;
        i ← i+1;
</syntaxhighlight>


'प्रक्रिया' इसॉर्ट (ए, बी, सटीक, स्वैप):
इस प्रक्रिया का उपयोग उपयोगकर्ता द्वारा निर्दिष्ट क्रम में मनमाने प्रकार के कुछ ऐरे ''x'' के ''x[a]'' से ''x[b]'' तक एलिमेंट को क्रमबद्ध करने के लिए किया जा सकता है। पैरामीटर prec और स्वैप दो फ़ंक्शन होने चाहिए, जो क्लाइंट द्वारा परिभाषित किए गए हैं, दोनों ''a'' और ''b'' के बीच दो पूर्णांक ''r,'' ''s'' लेते हैं। prec फ़ंक्शन को सत्य लौटना चाहिए यदि और केवल तभी जब क्लाइंट द्वारा परिभाषित क्रम में ''x[r]'' में संग्रहीत डेटा ''x[s]'' में संग्रहीत डेटा से पहले होना चाहिए। स्वैप फ़ंक्शन को ''x[r]'' और ''x[s]'' की सामग्री का आदान-प्रदान करना चाहिए, और कोई परिणाम नहीं लौटाना चाहिए।
    'पूर्णांक' i, j;
    मैं ← ए;
    'जबकि' मैं ≤ बी 'करो'
        जे ← मैं;
        'जबकि' j > a 'और' prec(j, j−1) 'do'
            स्वैप(जे, जे−1);
            जे ← जे−1;
        मैं ← मैं+1;


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


फ़ंक्शन प्रीक और स्वैप के उचित विकल्प द्वारा, उसी आइसोर्ट प्रक्रिया का उपयोग किसी भी [[डेटा प्रकार]] के सरणियों को पुन: व्यवस्थित करने के लिए किया जा सकता है, जो किसी भी माध्यम में संग्रहीत होता है और किसी भी डेटा संरचना में व्यवस्थित होता है जो व्यक्तिगत सरणी तत्वों तक अनुक्रमित पहुंच प्रदान करता है। (ध्यान दें कि ऐसे [[छँटाई एल्गोरिथ्म]] हैं जो बड़े सरणियों के लिए इंसर्शन सॉर्ट की तुलना में बहुत अधिक कुशल हैं।)
===फ़्लोटिंग-पॉइंट नंबरों को क्रमबद्ध करना===
उदाहरण के लिए, हम ''isort'' (1, 20,zprec,zswap) को कॉल करके बढ़ते क्रम में 20 फ़्लोटिंग-पॉइंट नंबरों, z[1] से z[20] की एक ऐरे ''z'' को सॉर्ट कर सकते हैं, जहां फ़ंक्शन zprec और zswap को इस प्रकार परिभाषित किया गया है<syntaxhighlight lang="pascal">
procedure zprec(r, s):
    return (z[r] < z[s]);


===फ़्लोटिंग-पॉइंट संख्याओं को क्रमबद्ध करना===
procedure zswap(r, s):
उदाहरण के लिए, हम आइसोर्ट (1, 20,zprec,zswap) को कॉल करके बढ़ते क्रम में 20 फ़्लोटिंग-पॉइंट नंबरों, z[1] से z[20] की एक सरणी z को सॉर्ट कर सकते हैं, जहां फ़ंक्शन zprec और zswap को इस प्रकार परिभाषित किया गया है
    float t;
 
    t z[r];
'प्रक्रिया' zprec(r, s):
    z[r] ← z[s];
    'वापसी' (z[r] < z[s]);
    z[s] ← t
</syntaxhighlight>
'प्रक्रिया' zswap(r, s):
    'फ्लोट' टी;
    टी जेड[आर];
    z[r] ← z[s];
    z[s] ← t


===मैट्रिक्स की पंक्तियों को क्रमबद्ध करना===
===मैट्रिक्स की पंक्तियों को क्रमबद्ध करना===
दूसरे उदाहरण के लिए, मान लीजिए कि M 10 पंक्तियों और 20 स्तंभों वाले पूर्णांकों का एक [[मैट्रिक्स (कंप्यूटिंग)]] है, जिसमें सूचकांक 1 से शुरू होते हैं। निम्नलिखित कोड प्रत्येक पंक्ति में तत्वों को पुनर्व्यवस्थित करेगा ताकि सभी सम मान सभी विषम मानों से पहले आएं:
एक अन्य उदाहरण के लिए, मान लीजिए कि ''M'' 10 पंक्तियों और 20 स्तंभों के साथ पूर्णांकों का [[मैट्रिक्स (कंप्यूटिंग)|मैट्रिक्स]] है, जिसका सूचकांक 1 से प्रारम्भ होता है। निम्नलिखित कोड प्रत्येक पंक्ति में एलिमेंट को पुनर्व्यवस्थित करेगा ताकि सभी सम मान सभी विषम मानों से पहले आएं:<syntaxhighlight lang="pascal">
integer i
procedure eoprec(r, s):
    return (M[i, r] mod 2) < (M[i, s] mod 2);


'पूर्णांक' मैं
procedure eoswap(r, s):
'प्रक्रिया' eoprec(r, s):
    integer t;
    'वापसी' (एम[आई, आर] 'मॉड' 2) < (एम[आई, एस] 'मॉड' 2);
    t M[i,r];
    M[i,r] ← M[i,s];
'प्रक्रिया' ईओस्वैप(आर, एस):
    M[i,s] ← t;
    'पूर्णांक' टी;
    टी एम[आई,आर];
    एम[आई,आर] ← एम[आई,एस];
    एम[आई,एस] ← टी;
'के लिए' मैं 1 'से' 10 तक 'करता हूं'
    आइसोर्ट(1, 20, ईओप्रेक, ईओस्वैप);


ध्यान दें कि eoprec और eoswap का प्रभाव पंक्ति संख्या i पर निर्भर करता है, लेकिन isort प्रक्रिया को यह जानने की आवश्यकता नहीं है।
for i from 1 to 10 do
    isort(1, 20, eoprec, eoswap);
</syntaxhighlight>ध्यान दें कि ''eoprec'' और ''eoswap'' का प्रभाव पंक्ति संख्या ''i'' पर निर्भर करता है, लेकिन ''isort'' प्रक्रिया को यह जानने की आवश्यकता नहीं है।


===वेक्टर-सॉर्टिंग प्रक्रिया===
===वेक्टर-सॉर्टिंग प्रक्रिया===
निम्नलिखित उदाहरण एक प्रक्रिया वेक्सोर्ट को परिभाषित करने के लिए आइसोर्ट का उपयोग करता है जो एक पूर्णांक n और एक पूर्णांक वेक्टर v को तत्वों v[0] से v[n−1] तक लेता है और उन्हें बढ़ते या घटते क्रम में क्रमबद्ध करता है, यह इस बात पर निर्भर करता है कि तीसरा पैरामीटर incr क्रमशः 'सही' या 'गलत' है या नहीं:
निम्नलिखित उदाहरण प्रक्रिया ''vecsort'' को परिभाषित करने के लिए ''isort'' का उपयोग करता है जो एलिमेंट ''v''[0] से ''v''[''n''−1] तक पूर्णांक ''n'' और पूर्णांक वेक्टर ''v'' लेता है और उन्हें बढ़ते या घटते क्रम में क्रमबद्ध करता है,  यह इस बात पर निर्भर करता है कि तीसरा पैरामीटर ''incr'' क्रमशः '''true''' है या '''false''':<syntaxhighlight lang="pascal">
procedure vecsort(n, v, incr):
 
    procedure vprec(r, s):
        if incr then
            return v[r] < v[s];
        else
            return v[r] > v[s];
 
    procedure vswap(r, s):
        integer t;
        t ← v[r];
        v[r] ← v[s];
        v[s] ← t
 
    isort(0, n−1, vprec, vswap);
</syntaxhighlight>फ़ंक्शन ''vprec'' प्राप्त करने के लिए नेस्टेड फ़ंक्शन परिभाषाओं के उपयोग पर ध्यान दें जिसका प्रभाव ''vecsort'' को दिए गए पैरामीटर ''incr'' पर निर्भर करता है। ऐसी भाषाओं में जो मानक C जैसी नेस्टेड फ़ंक्शन परिभाषाओं की अनुमति नहीं देती हैं, इस प्रभाव को प्राप्त करने के लिए जटिल और/या थ्रेड-असुरक्षित कोड की आवश्यकता होगी।
 
==उदाहरण: दो अनुक्रमों को मर्ज करना==
निम्नलिखित उदाहरण अमूर्त डेटा संरचनाओं को उनके ठोस कार्यान्वयन से स्वतंत्र रूप से संसाधित करने के लिए प्रक्रियात्मक पैरामीटर के उपयोग को दर्शाता है। समस्या रिकॉर्ड के दो क्रमबद्ध अनुक्रमों को एकल क्रमबद्ध अनुक्रम में विलय करने की है, जहां रिकॉर्ड की प्रकृति और ऑर्डरिंग पैरामीटर क्लाइंट द्वारा चुना जा सकता है। निम्नलिखित कार्यान्वयन केवल यह मानता है कि प्रत्येक रिकॉर्ड को मेमोरी एड्रेस द्वारा संदर्भित किया जा सकता है, और "नल एड्रेस" Λ है जो किसी भी वैध रिकॉर्ड का एड्रेस नहीं है। क्लाइंट को प्रत्येक क्रम में पहले रिकॉर्ड के ''A, B'' एड्रेस और बाद में वर्णित किए जाने वाले फ़ंक्शन ''prec'', ''next'' और ''append'' जिसका वर्णन बाद में किया जाएगा।<syntaxhighlight lang="pascal">
procedure merge(A, B, prec, nextA, appendA, nextB, appendB):
    address ini, fin, t
    ini ← Λ; fin ← Λ
    while A ≠ Λ or B ≠ Λ do
        if B = Λ or (A ≠ Λ and B ≠ Λ and prec(A, B)) then
            t ← nextA(A)
            fin ← appendA(A, fin); if ini = Λ then ini ← fin
            A ← t
        else
            t ← nextB(B)
            fin ← appendB(B, fin); if ini = Λ then ini ← fin
            B ← t
    return ini
</syntaxhighlight>फ़ंक्शन ''prec'' को दो रिकॉर्ड्स के एड्रेस ''r, s'' लेना चाहिए, प्रत्येक अनुक्रम से एक, और यदि पहला रिकॉर्ड आउटपुट अनुक्रम में दूसरे से पहले आना चाहिए तो सही लौटना चाहिए। फ़ंक्शन ''nextA'' को पहले अनुक्रम से एक रिकॉर्ड का एड्रेस लेना चाहिए, और उसी क्रम में अगले रिकॉर्ड का एड्रेस लौटाना चाहिए, या यदि कोई नहीं है तो Λ लौटाना चाहिए। फ़ंक्शन ''appendA'' को अनुक्रम ''A'' से आउटपुट अनुक्रम में पहला रिकॉर्ड जोड़ना चाहिए; इसके तर्क जोड़े जाने वाले रिकॉर्ड का एड्रेस ''A'' और आउटपुट सूची के अंतिम रिकॉर्ड का एड्रेस ''fin'' (या यदि वह सूची अभी भी खाली है) हैं। प्रक्रिया परिशिष्ट को आउटपुट सूची के अंतिम एलिमेंट का अद्यतन एड्रेस वापस करना चाहिए। ''nextB'' और ''appendB'' प्रक्रियाएं अन्य इनपुट अनुक्रम के अनुरूप हैं।


'प्रक्रिया' वेक्सोर्ट(एन, वी, इंसीआर):
===मर्जिंग लिंक्ड लिस्ट===
सामान्य मर्ज प्रक्रिया के उपयोग को स्पष्ट करने के लिए, यहां दो सरल लिंक की गई सूचियों को मर्ज करने के लिए कोड दिया गया है, जो पते ''R'', ''S'' पर नोड्स से प्रारम्भ होती है। यहां हम मानते हैं कि प्रत्येक रिकॉर्ड ''x'' में पूर्णांक फ़ील्ड ''x''.''INFO'' और एड्रेस फ़ील्ड ''x.NEXT'' होता है जो अगले नोड की ओर पॉइंट करता है; जहां प्रत्येक सूची में ''info'' फ़ील्ड बढ़ते क्रम में हैं। मर्ज द्वारा इनपुट सूचियों को नष्ट कर दिया जाता है, और उनके नोड्स का उपयोग आउटपुट सूची बनाने के लिए किया जाता है।<syntaxhighlight lang="pascal">
    'प्रक्रिया' vprec(r, s):
procedure listmerge(R, S):
        'अगर' बढ़ा 'तो'
            'वापसी' v[r] <v[s];
        'अन्य'
            'वापसी' v[r] > v[s];
    'प्रक्रिया' vswap(r, s):
        'पूर्णांक' टी;
        टी ← वी[आर];
        v[r] ← v[s];
        v[s] ← टी
    isort(0, n−1, vprec, vswap);


फ़ंक्शन vprec प्राप्त करने के लिए नेस्टेड फ़ंक्शन परिभाषाओं के उपयोग पर ध्यान दें, जिसका प्रभाव vecsort को दिए गए पैरामीटर incr पर निर्भर करता है। ऐसी लैंग्वेज में जो नेस्टेड फ़ंक्शन परिभाषाओं की अनुमति नहीं देती हैं, जैसे मानक C, इस प्रभाव को प्राप्त करने के लिए जटिल और/या थ्रेड सुरक्षा|थ्रेड-असुरक्षित कोड की आवश्यकता होगी।
    procedure prec(r, s):
        return r.INFO < s.INFO


==उदाहरण: दो अनुक्रमों का विलय==
    procedure next(x):
निम्नलिखित उदाहरण अमूर्त डेटा संरचनाओं को उनके ठोस कार्यान्वयन से स्वतंत्र रूप से संसाधित करने के लिए प्रक्रियात्मक मापदंडों के उपयोग को दर्शाता है। समस्या रिकॉर्ड्स के दो ऑर्डर किए गए अनुक्रमों को एक एकल क्रमबद्ध अनुक्रम में विलय करने की है, जहां क्लाइंट द्वारा रिकॉर्ड्स की प्रकृति और ऑर्डरिंग मानदंड को चुना जा सकता है। निम्नलिखित कार्यान्वयन केवल यह मानता है कि प्रत्येक रिकॉर्ड को एक मेमोरी पते द्वारा संदर्भित किया जा सकता है, और एक शून्य पता Λ है जो किसी भी वैध रिकॉर्ड का पता नहीं है। क्लाइंट को प्रत्येक क्रम में पहले रिकॉर्ड के ए, बी पते और बाद में वर्णित किए जाने वाले फ़ंक्शन प्री, नेक्स्ट और अपेंड प्रदान करने होंगे।
        return x.NEXT


'प्रक्रिया' मर्ज (, बी, सटीक, अगलाए, परिशिष्टए, अगलाबी, परिशिष्टबी):
    procedure append(x, fin)
    'पता' आईएनआई, फिन, टी
        if fin ≠ Λ then fin.NEXT ← x
    ini ← Λ; फिन ← Λ
        x.NEXT ← Λ
     'जबकि' A ≠ Λ या B ≠ Λ 'करें'
        return x
        'यदि' B = Λ 'या' (A ≠ Λ 'और' B ≠ Λ 'और' prec(A, B)) 'तब'
      
            t ← अगलाA(A)
    return merge(R, S, prec, next, append, next, append)
            फिन ← परिशिष्टए(ए, फिन); 'अगर' आईएनआई = Λ 'तब' आईएनआई ← फिन
</syntaxhighlight>
            ए ← टी
        'अन्य'
            t ← अगलाB(B)
            फिन ← एपेंडबी(बी, फिन); 'अगर' आईएनआई = Λ 'तब' आईएनआई ← फिन
            बी ← टी
    'वापसी' ini


फ़ंक्शन प्रीक को दो रिकॉर्ड्स के पते r, s लेना चाहिए, प्रत्येक अनुक्रम से एक, और आउटपुट अनुक्रम में पहला रिकॉर्ड दूसरे से पहले आने पर 'सही' लौटाना चाहिए। फ़ंक्शन नेक्स्टए को पहले अनुक्रम से एक रिकॉर्ड का पता लेना चाहिए, और उसी क्रम में अगले रिकॉर्ड का पता लौटाना चाहिए, या यदि कोई नहीं है तो Λ लौटाना चाहिए। फ़ंक्शन एपेंडए को अनुक्रम से आउटपुट अनुक्रम में पहला रिकॉर्ड जोड़ना चाहिए; इसके तर्क जोड़े जाने वाले रिकॉर्ड का पता A और आउटपुट सूची के अंतिम रिकॉर्ड का पता फिन (या यदि वह सूची अभी भी खाली है) हैं। प्रक्रिया परिशिष्ट को आउटपुट सूची के अंतिम तत्व का अद्यतन पता वापस करना चाहिए। नेक्स्टबी और एपेंडबी प्रक्रियाएं अन्य इनपुट अनुक्रम के अनुरूप हैं।
===मर्जिंग वेक्टर्स===
निम्नलिखित कोड अनुक्रमों के वास्तविक प्रतिनिधित्व से सामान्य मर्ज प्रक्रिया की स्वतंत्रता को दर्शाता है। यह दो साधारण सरणियों ''U''[0] से ''U''[''m''−1] और ''V''[0] से ''V''[''n''−1] तक फ्लोटिंग-पॉइंट संख्याओं के एलिमेंट को घटते क्रम में मिलाता है। इनपुट सरणियों को संशोधित नहीं किया गया है, और मानों का मर्ज किया गया अनुक्रम ''W''[''m''+''n''−1] के माध्यम से तीसरे वेक्टर ''W''[0] में संग्रहीत किया जाता है। जैसा कि C प्रोग्रामिंग लैंग्वेज में है, हम मानते हैं कि अभिव्यक्ति "&''V''" वेरिएबल ''V'' का एड्रेस देता है, "*''p''" वह वेरिएबल देता है जिसका एड्रेस ''p'' का मान है, और "&(''X''[''i''])" किसी भी ऐरे X और किसी पूर्णांक ''i'' के लिए "&(''X''[0]) + ''i''" के बराबर है।<syntaxhighlight lang="pascal">
procedure arraymerge(U, m, V, n, W):


===लिंक की गई सूचियों का विलय===
    procedure prec(r, s):
सामान्य मर्ज प्रक्रिया के उपयोग को स्पष्ट करने के लिए, यहां दो सरल लिंक की गई सूचियों को मर्ज करने के लिए कोड दिया गया है, जो पते आर, एस पर नोड्स से शुरू होती है। यहां हम मानते हैं कि प्रत्येक रिकॉर्ड x में एक पूर्णांक फ़ील्ड x.INFO और एक पता फ़ील्ड x.NEXT होता है जो अगले नोड को इंगित करता है; जहां प्रत्येक सूची में सूचना फ़ील्ड बढ़ते क्रम में हैं। मर्ज द्वारा इनपुट सूचियों को नष्ट कर दिया जाता है, और उनके नोड्स का उपयोग आउटपुट सूची बनाने के लिए किया जाता है।
        return (*r) > (*s)


'प्रक्रिया' सूची मर्ज (आर, एस):
    procedure nextU(x):
        if x = &(U[m−1]) then return Λ else return x + 1
    'प्रक्रिया' पूर्व(आर, एस):
        'वापसी' r.INFO < s.INFO
    'प्रक्रिया' अगला(x):
        'वापसी' x.अगला
    'प्रक्रिया' परिशिष्ट (एक्स, फिन)
        'अगर' फिन ≠ Λ 'तो' फिन.अगला ← एक्स
        x.अगला ← Λ
        'वापसी' एक्स
     
    'वापसी' मर्ज (आर, एस, सटीक, अगला, जोड़ें, अगला, जोड़ें)


===वेक्टरों का विलय===
    procedure nextV(x):
निम्नलिखित कोड अनुक्रमों के वास्तविक प्रतिनिधित्व से सामान्य मर्ज प्रक्रिया की स्वतंत्रता को दर्शाता है। यह दो साधारण सरणियों U[0] से U[m−1] और V[0] से V[n−1] तक फ्लोटिंग-पॉइंट संख्याओं के तत्वों को घटते क्रम में मिलाता है। इनपुट सरणियों को संशोधित नहीं किया गया है, और मानों का मर्ज किया गया अनुक्रम W[m+n−1] के माध्यम से तीसरे वेक्टर W[0] में संग्रहीत किया जाता है। जैसा कि C प्रोग्रामिंग भाषा में है, हम मानते हैं कि अभिव्यक्ति &V वेरिएबल V का पता देता है, *p वह वेरिएबल देता है जिसका पता p का मान है, और &(X[i]) किसी भी सरणी X और किसी पूर्णांक i के लिए &(X[0]) + i के बराबर है।
        if x = &(V[n−1]) then return Λ else return x + 1


'प्रक्रिया' सरणीमर्ज (यू, एम, वी, एन, डब्ल्यू):
    procedure append(x, fin)
        if fin = Λ then fin ← &(W[0])
    'प्रक्रिया' पूर्व(आर, एस):
        (*fin) ← (*x)
        'वापसी' (*r) > (*s)
        return fin + 1
       
    'प्रक्रिया' अगलाU(x):
    if m = 0 then U ← Λ
        'अगर' x = &(U[m−1]) 'तो' 'वापसी' Λ 'अन्यथा' 'वापसी' x + 1
    if n = 0 then V ← Λ
    return merge(U, V, prec, nextU, append, nextV, append)
    'प्रक्रिया' अगलाV(x):
</syntaxhighlight>
        'अगर' x = &(V[n−1]) 'तो' 'वापसी' Λ 'अन्यथा' 'वापसी' x + 1
    'प्रक्रिया' परिशिष्ट (एक्स, फिन)
        'if' fin = Λ 'then' fin ← &(W[0])
        (*फिन) ← (*x)
        'वापसी' फिन + 1
       
    'यदि' m = 0 तो U ← Λ
    'यदि' n = 0 तो V ← Λ
    'वापसी' मर्ज (यू, वी, प्रीक, नेक्स्टयू, अपेंड, नेक्स्टवी, अपेंड)


==उदाहरण: निश्चित अभिन्न==
==उदाहरण: निश्चित अभिन्न==


===एक अंतराल पर एकीकृत करना===
===इंटेग्रटिंग ओवर एन इंटरवल===
निम्नलिखित प्रक्रिया अनुमानित [[अभिन्न (गणित)]] की गणना करती है <math>\textstyle\int_a^b</math> [[वास्तविक संख्या]] के दिए गए अंतराल [ए,बी] पर किसी दिए गए वास्तविक-मूल्यवान [[फ़ंक्शन (गणित)]] का एफ (एक्स) डीएक्स। उपयोग की जाने वाली [[संख्यात्मक विधि]] चरणों की दी गई संख्या n के साथ [[ट्रैपेज़ियम नियम]] है; वास्तविक संख्याएँ फ़्लोटिंग-पॉइंट संख्याओं द्वारा अनुमानित की जाती हैं।
निम्नलिखित प्रक्रिया वास्तविक रेखा के दिए गए इंटरवल ''[a,b]'' पर दिए गए वास्तविक-मूल्य वाले फ़ंक्शन f के अनुमानित अभिन्न <math>\textstyle\int_a^b</math>''f'' (''x'') d''x'' की गणना करती है। उपयोग की जाने वाली संख्यात्मक विधि चरणों की दी गई संख्या ''n'' के साथ ट्रैपेज़ियम नियम है; वास्तविक संख्याएँ फ़्लोटिंग-पॉइंट संख्याओं द्वारा अनुमानित की जाती हैं<syntaxhighlight lang="pascal">
procedure Intg(f, a, b, n):
    float t, x, s; integer i
    if b = a then return 0
    x ← a; s ← f(a) / 2;
    for i from 1 to n−1 do
        t ← i/(n+1); x ← (1−t) * a + t * b;
        s ← s + f(x)
    s ← f(b) / 2
    return (b − a) * s / n
</syntaxhighlight>
 
===इंटेग्रटिंग ओवर ए  डिस्क===
अब किसी दिए गए फ़ंक्शन <math>g</math> को एकीकृत करने की समस्या पर विचार करें, दो तर्कों के साथ, डिस्क <math>D</math> पर दिए गए केंद्र के साथ (<math>xc,yc</math>) और त्रिज्या <math>R</math> दी गई है चर के परिवर्तन से इस समस्या को दो नेस्टेड एकल-चर इंटीग्रल में कम किया जा सकता है


'प्रक्रिया' Intg(f, a, b, n):
:<math>\int\!\int_D g(x,y)\, \mathrm{d}x\, \mathrm{d}y = \int_0^R  z  \left(\int_0^{2\pi} g(\mathit{xc}+z \cos t ,\mathit{yc}+z \sin t ) \,\mathrm{d}t\right)\,\mathrm{d}z</math>
    'फ्लोट' टी, एक्स, एस; 'पूर्णांक' मैं
निम्नलिखित कोड दाहिनी ओर का फॉर्मूला लागू करता है:<syntaxhighlight lang="pascal">
    'अगर' बी = ए 'तो' 'वापसी' 0
procedure DiskIntg(g, xc, yc, R, n)
    एक्स ← ए; s ← f(a) / 2;
    'के लिए' i 'से' 1 'से' n−1 'करें'
        t ← i/(n+1); x ← (1−t) * a + t * b;
        s ← s + f(x)
    s ← f(b) / 2
    'वापसी' (बी - ए) * एस / एन


===डिस्क पर एकीकरण===
    procedure gring(z):
अब किसी दिए गए फ़ंक्शन को एकीकृत करने की समस्या पर विचार करें <math>g</math>, दो तर्कों के साथ, एक डिस्क पर <math>D</math> दिए गए केंद्र के साथ (<math>xc,yc</math>) और त्रिज्या दी गई है <math>R</math>. चर के परिवर्तन से इस समस्या को दो नेस्टेड एकल-चर इंटीग्रल में कम किया जा सकता है


:<math>\int\!\int_D g(x,y)\, \mathrm{d}x\, \mathrm{d}y = \int_0^R  z  \left(\int_0^{2\pi} g(\mathit{xc}+z \cos t ,\mathit{yc}+z \sin t ) \,\mathrm{d}t\right)\,\mathrm{d}z</math>
        procedure gpolar(t):
निम्नलिखित कोड एक समीकरण के पक्षों को लागू करता है|दाहिने हाथ का सूत्र:
            float x, y
            x xc + z * cos(t)
            y ← yc + z * sin(t)
            return g(x, y)


प्रक्रिया ''DiskIntg''(''g'', ''xc'', ''yc'', ''R'', ''n'')
        integer m ← round(n*z/R)
        return z * Intg(gpolar, 0, 2*π, m)
    प्रक्रिया ''gring''(''z''):
        प्रक्रिया ''जीपोलर''(''टी''):
            फ़्लोट ''x'', ''y''
            ''x'' ← ''xc'' + ''z'' * ''cos''(''t'')
            ''y'' ← ''yc'' + ''z'' * ''sin''(''t'')
            वापसी ''जी''(''एक्स'', ''वाई'')
        पूर्णांक ''m'' ''गोल''(''n''*''z''/''R'')
        वापसी ''z'' * ''Intg''(''gpolar'', 0, 2*π, ''m'')
    वापसी ''इंटग''(''ग्रिंग'', 0, ''आर'', ''एन'')


यह कोड दो स्तरों में एकीकरण प्रक्रिया ''Intg'' का उपयोग करता है। बाहरी स्तर (अंतिम पंक्ति) के अभिन्न अंग की गणना करने के लिए ''Intg'' का उपयोग करता है <math>gring(z)</math> के लिए <math>z</math> 0 से भिन्न होता है <math>R</math>. आंतरिक स्तर (अंतिम से अगली पंक्ति) परिभाषित करता है <math>gring(z)</math> का अभिन्न अंग होने के नाते <math>g(x,y)</math> केंद्र वाले वृत्त के ऊपर <math>(xc,yc)</math> और त्रिज्या <math>z</math>.
    return Intg(gring, 0, R, n)
</syntaxhighlight>यह कोड दो स्तरों में एकीकरण प्रक्रिया ''Intg'' का उपयोग करता है। बाहरी स्तर (अंतिम पंक्ति) 0 से <math>R</math> तक भिन्न <math>z</math> के लिए <math>gring(z)</math> के अभिन्न अंग की गणना करने के लिए ''Intg'' का उपयोग करता है। आंतरिक स्तर (अंतिम से अगली पंक्ति) केंद्र <math>(xc,yc)</math> और त्रिज्या <math>z</math> वाले वृत्त पर <math>g(x,y)</math> की रेखा अभिन्न अंग के रूप में <math>gring(z)</math> को परिभाषित करता है।


==इतिहास==
==इतिहास==
<!--DATES NEEDED-->प्रक्रियात्मक मापदंडों का आविष्कार इलेक्ट्रॉनिक कंप्यूटर के युग से पहले, [[गणितज्ञ]] [[अलोंजो चर्च]] द्वारा, गणना के उनके [[लैम्ब्डा कैलकुलस]] मॉडल के हिस्से के रूप में किया गया था।
प्रक्रियात्मक पैरामीटर का आविष्कार इलेक्ट्रॉनिक कंप्यूटर के युग से पहले, [[गणितज्ञ]] [[अलोंजो चर्च]] द्वारा, गणना के उनके [[लैम्ब्डा कैलकुलस|लैम्ब्डा-कैलकुलस]] मॉडल के हिस्से के रूप में किया गया था।


प्रोग्रामिंग भाषा सुविधा के रूप में प्रक्रियात्मक पैरामीटर [[ALGOL 60 प्रोग्रामिंग भाषा]] द्वारा पेश किए गए थे।<!--DID FORTRAN IV HAVE SOMETHING LIKE THAT TOO? NOT SURE...--> वास्तव में, ALGOL 60 में नाम पैरामीटर-पासिंग तंत्र द्वारा एक शक्तिशाली कॉल था जो प्रक्रियात्मक पैरामीटर के कुछ उपयोगों को सरल बना सकता था; जेन्सेन का उपकरण देखें।
प्रोग्रामिंग लैंग्वेज सुविधा के रूप में प्रक्रियात्मक पैरामीटर [[ALGOL 60 प्रोग्रामिंग भाषा|ALGOL 60]] द्वारा पेश किए गए थे। वास्तव में, ALGOL 60 में एक प्रभावी "कॉल बाय नेम" पैरामीटर-पासिंग तंत्र था जो प्रक्रियात्मक पैरामीटर के कुछ उपयोगों को सरल बना सकता था; जेन्सेन का उपकरण देखें।


प्रक्रियात्मक पैरामीटर [[एलआईएसपी प्रोग्रामिंग भाषा]] की एक अनिवार्य विशेषता थी, जिसने फ़ंक्शन क्लोजर या [[फनर्ग]] की अवधारणा भी पेश की। C (प्रोग्रामिंग भाषा) [[फ़ंक्शन सूचक]] को पैरामीटर के रूप में पारित करने की अनुमति देता है<!--FROM THE BEGINNING?-->, जो समान उद्देश्य को पूरा करते हैं, और अक्सर [[घटना-संचालित प्रोग्रामिंग]] में [[कॉलबैक]] और त्रुटि हैंडलर के रूप में उपयोग किए जाते हैं। हालाँकि, केवल कुछ आधुनिक C कंपाइलर नेस्टेड फ़ंक्शन परिभाषाओं की अनुमति देते हैं, ताकि इसके अन्य उपयोग अपेक्षाकृत असामान्य हों। नेस्टेड प्रक्रिया परिभाषाओं के साथ, प्रक्रियात्मक पैरामीटर पास्कल में भी प्रदान किए गए थे; हालाँकि, चूँकि मानक पास्कल ने अलग संकलन की अनुमति नहीं दी थी, इसलिए उस भाषा में भी इस सुविधा का बहुत कम उपयोग किया गया था।
प्रक्रियात्मक पैरामीटर [[एलआईएसपी प्रोग्रामिंग भाषा|एलआईएसपी प्रोग्रामिंग लैंग्वेज]] की अनिवार्य विशेषता थी, जिसने फ़ंक्शन क्लोजर या फनर्ग की अवधारणा भी पेश की। C प्रोग्रामिंग लैंग्वेज फ़ंक्शन पॉइंटर्स को पैरामीटर के रूप में पारित करने की अनुमति देती है, जो समान अंत को पूरा करती है, और प्रायः इवेंट-संचालित प्रोग्रामिंग में कॉलबैक और त्रुटि हैंडलर के रूप में उपयोग की जाती है। हालाँकि, केवल कुछ आधुनिक C कंपाइलर नेस्टेड फ़ंक्शन परिभाषाओं की अनुमति देते हैं, ताकि इसके अन्य उपयोग अपेक्षाकृत असामान्य हों। नेस्टेड प्रक्रिया परिभाषाओं के साथ, प्रक्रियात्मक पैरामीटर पास्कल में भी प्रदान किए गए थे; हालाँकि, चूँकि मानक पास्कल ने अलग संकलन की अनुमति नहीं दी थी, इसलिए उस लैंग्वेज में भी इस सुविधा का बहुत कम उपयोग किया गया था।


==यह भी देखें==
==यह भी देखें==
*[[फ़ंक्शन सूचक]]
*[[फ़ंक्शन सूचक|फंक्शन पॉइंटर]]
*[[कार्यात्मक प्रोग्रामिंग]]
*[[कार्यात्मक प्रोग्रामिंग|फंक्शनल प्रोग्रामिंग]]
*[[फनर्ग समस्या]]
*[[फनर्ग समस्या]]
*[[डिज़ाइन पैटर्न (कंप्यूटर विज्ञान)]]
*[[डिज़ाइन पैटर्न (कंप्यूटर विज्ञान)]]
{{Unreferenced|date=December 2009}}


{{DEFAULTSORT:Procedural Parameter}}
{{DEFAULTSORT:Procedural Parameter}}


श्रेणी:सबरूटीन्स
[[Category:Created On 26/07/2023|Procedural Parameter]]
 
[[Category:Machine Translated Page|Procedural Parameter]]
 
[[Category: Machine Translated Page]]
[[Category:Created On 26/07/2023]]

Latest revision as of 18:14, 8 August 2023

कम्प्यूटिंग में, प्रक्रियात्मक पैरामीटर प्रक्रिया का एक पैरामीटर होता है जो स्वयं एक प्रक्रिया होती है।

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

यह उपकरण उन लैंग्वेज में विशेष रूप से प्रभावी और सुविधाजनक है जो लोकल फ़ंक्शन परिभाषाओं जैसे पास्कल और C की आधुनिक जीएनयू लैंग्वेज का समर्थन करते हैं। यह तब और भी अधिक होता है जब फ़ंक्शन क्लोजर उपलब्ध होते हैं। ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग लैंग्वेज में ऑब्जेक्ट द्वारा समान कार्यक्षमता (और अधिक) लेकिन काफी अधिक कीमत पर प्रदान की जाती है।

प्रक्रियात्मक पैरामीटर कुछ हद तक प्रथम श्रेणी फ़ंक्शन और एनोनिमस फ़ंक्शन की अवधारणाओं से संबंधित हैं, लेकिन उनसे अलग हैं। इन दोनों अवधारणाओं का संबंध इस बात से अधिक है कि फ़ंक्शन को कैसे परिभाषित किया जाता है, न कि उनका उपयोग कैसे किया जाता है।

मूल अवधारणा

यह सुविधा प्रदान करने वाली अधिकांश लैंग्वेज में, सबरूटीन P के एक प्रक्रियात्मक पैरामीटर f को P के बॉडी के अंदर कॉल किया जा सकता है जैसे कि यह एक सामान्य प्रक्रिया थी:

procedure P(f):
    return f(6,3) * f(2,1)

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

procedure plus(x, y):
    return x + y

तो हम P (plus) कह सकते हैं, और परिणाम plus(6,3) * plus(2,1) = (6 + 3)*(2 + 1) = 27 होगा। दूसरी ओर, यदि हम परिभाषित करते हैं।

procedure quot(u, v):
    return u/v

फिर P (quot) को कॉल करने पर quot(6,3)*quot(2,1) = (6/3)*(2/1) = 4 आएगा। अंत में, यदि हम परिभाषित करते हैं

procedure evil(z)
    return z + 100

तब कॉल P (evil) का कोई विशेष अर्थ नहीं होगा, और इसे एक त्रुटि के रूप में चिह्नित किया जा सकता है।

वाक्यविन्यास विवरण

कुछ प्रोग्रामिंग भाषाएं जिनमें यह सुविधा है, वे प्रत्येक प्रक्रियात्मक पैरामीटर f के लिए एक पूर्ण प्रकार की घोषणा की अनुमति दे सकती हैं या इसकी आवश्यकता हो सकती है, जिसमें इसके तर्कों की संख्या और प्रकार और इसके परिणाम का प्रकार, यदि कोई हो, सम्मिलित है। उदाहरण के लिए, C प्रोग्रामिंग लैंग्वेज में, ऊपर दिए गए उदाहरण को इस प्रकार लिखा जा सकता है

int P(int (*f)(int a, int b)) {
    return f(6,3) * f(2,1);
}

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

स्कोपिंग

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

इन दायरे नियमों का कार्यान्वयन साधारण नहीं है। जब तक actf अंततः निष्पादित होता है, तब तक सक्रियण रिकॉर्ड जहां इसके पर्यावरण चर रहते हैं, स्टैक में अनियमित ढंग से गहरे हो सकते हैं। यह तथाकथित डाउनवर्ड फ़नर्ग समस्या है।

उदाहरण: जेनेरिक इंसर्शन सॉर्ट

प्रक्रियात्मक पैरामीटर की अवधारणा को उदाहरणों द्वारा सर्वोत्तम रूप से समझाया गया है। एक विशिष्ट एप्लिकेशन इंसर्शन सॉर्ट एल्गोरिदम का निम्नलिखित सामान्य कार्यान्वयन है, जो दो पूर्णांक पैरामीटर a, b और दो प्रक्रियात्मक पैरामीटर prec, स्वैप लेता है:

procedure isort(a, b, prec, swap):
    integer i, j;
    i  a;
    while i  b do
        j  i;
        while j > a and prec(j, j1) do
            swap(j, j1);
            j  j1;
        i  i+1;

इस प्रक्रिया का उपयोग उपयोगकर्ता द्वारा निर्दिष्ट क्रम में मनमाने प्रकार के कुछ ऐरे x के x[a] से x[b] तक एलिमेंट को क्रमबद्ध करने के लिए किया जा सकता है। पैरामीटर prec और स्वैप दो फ़ंक्शन होने चाहिए, जो क्लाइंट द्वारा परिभाषित किए गए हैं, दोनों a और b के बीच दो पूर्णांक r, s लेते हैं। prec फ़ंक्शन को सत्य लौटना चाहिए यदि और केवल तभी जब क्लाइंट द्वारा परिभाषित क्रम में x[r] में संग्रहीत डेटा x[s] में संग्रहीत डेटा से पहले होना चाहिए। स्वैप फ़ंक्शन को x[r] और x[s] की सामग्री का आदान-प्रदान करना चाहिए, और कोई परिणाम नहीं लौटाना चाहिए।

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

फ़्लोटिंग-पॉइंट नंबरों को क्रमबद्ध करना

उदाहरण के लिए, हम isort (1, 20,zprec,zswap) को कॉल करके बढ़ते क्रम में 20 फ़्लोटिंग-पॉइंट नंबरों, z[1] से z[20] की एक ऐरे z को सॉर्ट कर सकते हैं, जहां फ़ंक्शन zprec और zswap को इस प्रकार परिभाषित किया गया है

procedure zprec(r, s):
    return (z[r] < z[s]);

procedure zswap(r, s):
    float t;
    t  z[r];
    z[r]  z[s];
    z[s]  t

मैट्रिक्स की पंक्तियों को क्रमबद्ध करना

एक अन्य उदाहरण के लिए, मान लीजिए कि M 10 पंक्तियों और 20 स्तंभों के साथ पूर्णांकों का मैट्रिक्स है, जिसका सूचकांक 1 से प्रारम्भ होता है। निम्नलिखित कोड प्रत्येक पंक्ति में एलिमेंट को पुनर्व्यवस्थित करेगा ताकि सभी सम मान सभी विषम मानों से पहले आएं:

integer i
procedure eoprec(r, s):
    return (M[i, r] mod 2) < (M[i, s] mod 2);

procedure eoswap(r, s):
    integer t;
    t  M[i,r];
    M[i,r]  M[i,s];
    M[i,s]  t;

for i from 1 to 10 do
    isort(1, 20, eoprec, eoswap);

ध्यान दें कि eoprec और eoswap का प्रभाव पंक्ति संख्या i पर निर्भर करता है, लेकिन isort प्रक्रिया को यह जानने की आवश्यकता नहीं है।

वेक्टर-सॉर्टिंग प्रक्रिया

निम्नलिखित उदाहरण प्रक्रिया vecsort को परिभाषित करने के लिए isort का उपयोग करता है जो एलिमेंट v[0] से v[n−1] तक पूर्णांक n और पूर्णांक वेक्टर v लेता है और उन्हें बढ़ते या घटते क्रम में क्रमबद्ध करता है,  यह इस बात पर निर्भर करता है कि तीसरा पैरामीटर incr क्रमशः true है या false:

procedure vecsort(n, v, incr):

    procedure vprec(r, s):
        if incr then
            return v[r] < v[s];
        else
            return v[r] > v[s];

    procedure vswap(r, s):
        integer t;
        t  v[r];
        v[r]  v[s];
        v[s]  t

    isort(0, n1, vprec, vswap);

फ़ंक्शन vprec प्राप्त करने के लिए नेस्टेड फ़ंक्शन परिभाषाओं के उपयोग पर ध्यान दें जिसका प्रभाव vecsort को दिए गए पैरामीटर incr पर निर्भर करता है। ऐसी भाषाओं में जो मानक C जैसी नेस्टेड फ़ंक्शन परिभाषाओं की अनुमति नहीं देती हैं, इस प्रभाव को प्राप्त करने के लिए जटिल और/या थ्रेड-असुरक्षित कोड की आवश्यकता होगी।

उदाहरण: दो अनुक्रमों को मर्ज करना

निम्नलिखित उदाहरण अमूर्त डेटा संरचनाओं को उनके ठोस कार्यान्वयन से स्वतंत्र रूप से संसाधित करने के लिए प्रक्रियात्मक पैरामीटर के उपयोग को दर्शाता है। समस्या रिकॉर्ड के दो क्रमबद्ध अनुक्रमों को एकल क्रमबद्ध अनुक्रम में विलय करने की है, जहां रिकॉर्ड की प्रकृति और ऑर्डरिंग पैरामीटर क्लाइंट द्वारा चुना जा सकता है। निम्नलिखित कार्यान्वयन केवल यह मानता है कि प्रत्येक रिकॉर्ड को मेमोरी एड्रेस द्वारा संदर्भित किया जा सकता है, और "नल एड्रेस" Λ है जो किसी भी वैध रिकॉर्ड का एड्रेस नहीं है। क्लाइंट को प्रत्येक क्रम में पहले रिकॉर्ड के A, B एड्रेस और बाद में वर्णित किए जाने वाले फ़ंक्शन prec, next और append जिसका वर्णन बाद में किया जाएगा।

procedure merge(A, B, prec, nextA, appendA, nextB, appendB):
    address ini, fin, t
    ini  Λ; fin  Λ
    while A  Λ or B  Λ do
        if B = Λ or (A  Λ and B  Λ and prec(A, B)) then
            t  nextA(A)
            fin  appendA(A, fin); if ini = Λ then ini  fin
            A  t
        else
            t  nextB(B)
            fin  appendB(B, fin); if ini = Λ then ini  fin
            B  t
    return ini

फ़ंक्शन prec को दो रिकॉर्ड्स के एड्रेस r, s लेना चाहिए, प्रत्येक अनुक्रम से एक, और यदि पहला रिकॉर्ड आउटपुट अनुक्रम में दूसरे से पहले आना चाहिए तो सही लौटना चाहिए। फ़ंक्शन nextA को पहले अनुक्रम से एक रिकॉर्ड का एड्रेस लेना चाहिए, और उसी क्रम में अगले रिकॉर्ड का एड्रेस लौटाना चाहिए, या यदि कोई नहीं है तो Λ लौटाना चाहिए। फ़ंक्शन appendA को अनुक्रम A से आउटपुट अनुक्रम में पहला रिकॉर्ड जोड़ना चाहिए; इसके तर्क जोड़े जाने वाले रिकॉर्ड का एड्रेस A और आउटपुट सूची के अंतिम रिकॉर्ड का एड्रेस fin (या यदि वह सूची अभी भी खाली है) हैं। प्रक्रिया परिशिष्ट को आउटपुट सूची के अंतिम एलिमेंट का अद्यतन एड्रेस वापस करना चाहिए। nextB और appendB प्रक्रियाएं अन्य इनपुट अनुक्रम के अनुरूप हैं।

मर्जिंग लिंक्ड लिस्ट

सामान्य मर्ज प्रक्रिया के उपयोग को स्पष्ट करने के लिए, यहां दो सरल लिंक की गई सूचियों को मर्ज करने के लिए कोड दिया गया है, जो पते R, S पर नोड्स से प्रारम्भ होती है। यहां हम मानते हैं कि प्रत्येक रिकॉर्ड x में पूर्णांक फ़ील्ड x.INFO और एड्रेस फ़ील्ड x.NEXT होता है जो अगले नोड की ओर पॉइंट करता है; जहां प्रत्येक सूची में info फ़ील्ड बढ़ते क्रम में हैं। मर्ज द्वारा इनपुट सूचियों को नष्ट कर दिया जाता है, और उनके नोड्स का उपयोग आउटपुट सूची बनाने के लिए किया जाता है।

procedure listmerge(R, S):

    procedure prec(r, s):
        return r.INFO < s.INFO

    procedure next(x):
        return x.NEXT

    procedure append(x, fin)
        if fin  Λ then fin.NEXT  x
        x.NEXT  Λ
        return x
     
    return merge(R, S, prec, next, append, next, append)

मर्जिंग वेक्टर्स

निम्नलिखित कोड अनुक्रमों के वास्तविक प्रतिनिधित्व से सामान्य मर्ज प्रक्रिया की स्वतंत्रता को दर्शाता है। यह दो साधारण सरणियों U[0] से U[m−1] और V[0] से V[n−1] तक फ्लोटिंग-पॉइंट संख्याओं के एलिमेंट को घटते क्रम में मिलाता है। इनपुट सरणियों को संशोधित नहीं किया गया है, और मानों का मर्ज किया गया अनुक्रम W[m+n−1] के माध्यम से तीसरे वेक्टर W[0] में संग्रहीत किया जाता है। जैसा कि C प्रोग्रामिंग लैंग्वेज में है, हम मानते हैं कि अभिव्यक्ति "&V" वेरिएबल V का एड्रेस देता है, "*p" वह वेरिएबल देता है जिसका एड्रेस p का मान है, और "&(X[i])" किसी भी ऐरे X और किसी पूर्णांक i के लिए "&(X[0]) + i" के बराबर है।

procedure arraymerge(U, m, V, n, W):

    procedure prec(r, s):
        return (*r) > (*s)

    procedure nextU(x):
        if x = &(U[m1]) then return Λ else return x + 1

    procedure nextV(x):
        if x = &(V[n1]) then return Λ else return x + 1

    procedure append(x, fin)
        if fin = Λ then fin  &(W[0])
        (*fin)  (*x)
        return fin + 1
        
    if m = 0 then U  Λ
    if n = 0 then V  Λ
    return merge(U, V, prec, nextU, append, nextV, append)

उदाहरण: निश्चित अभिन्न

इंटेग्रटिंग ओवर एन इंटरवल

निम्नलिखित प्रक्रिया वास्तविक रेखा के दिए गए इंटरवल [a,b] पर दिए गए वास्तविक-मूल्य वाले फ़ंक्शन f के अनुमानित अभिन्न f (x) dx की गणना करती है। उपयोग की जाने वाली संख्यात्मक विधि चरणों की दी गई संख्या n के साथ ट्रैपेज़ियम नियम है; वास्तविक संख्याएँ फ़्लोटिंग-पॉइंट संख्याओं द्वारा अनुमानित की जाती हैं

procedure Intg(f, a, b, n):
    float t, x, s; integer i
    if b = a then return 0
    x  a; s  f(a) / 2;
    for i from 1 to n1 do
        t  i/(n+1); x  (1t) * a + t * b;
        s  s + f(x)
    s  f(b) / 2
    return (b  a) * s / n

इंटेग्रटिंग ओवर ए  डिस्क

अब किसी दिए गए फ़ंक्शन को एकीकृत करने की समस्या पर विचार करें, दो तर्कों के साथ, डिस्क पर दिए गए केंद्र के साथ () और त्रिज्या दी गई है चर के परिवर्तन से इस समस्या को दो नेस्टेड एकल-चर इंटीग्रल में कम किया जा सकता है

निम्नलिखित कोड दाहिनी ओर का फॉर्मूला लागू करता है:

procedure DiskIntg(g, xc, yc, R, n)

    procedure gring(z):

        procedure gpolar(t):
            float x, y
            x  xc + z * cos(t)
            y  yc + z * sin(t)
            return g(x, y)

        integer m  round(n*z/R)
        return z * Intg(gpolar, 0, 2*π, m)

    return Intg(gring, 0, R, n)

यह कोड दो स्तरों में एकीकरण प्रक्रिया Intg का उपयोग करता है। बाहरी स्तर (अंतिम पंक्ति) 0 से तक भिन्न के लिए के अभिन्न अंग की गणना करने के लिए Intg का उपयोग करता है। आंतरिक स्तर (अंतिम से अगली पंक्ति) केंद्र और त्रिज्या वाले वृत्त पर की रेखा अभिन्न अंग के रूप में को परिभाषित करता है।

इतिहास

प्रक्रियात्मक पैरामीटर का आविष्कार इलेक्ट्रॉनिक कंप्यूटर के युग से पहले, गणितज्ञ अलोंजो चर्च द्वारा, गणना के उनके लैम्ब्डा-कैलकुलस मॉडल के हिस्से के रूप में किया गया था।

प्रोग्रामिंग लैंग्वेज सुविधा के रूप में प्रक्रियात्मक पैरामीटर ALGOL 60 द्वारा पेश किए गए थे। वास्तव में, ALGOL 60 में एक प्रभावी "कॉल बाय नेम" पैरामीटर-पासिंग तंत्र था जो प्रक्रियात्मक पैरामीटर के कुछ उपयोगों को सरल बना सकता था; जेन्सेन का उपकरण देखें।

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

यह भी देखें