प्रक्रियात्मक पैरामीटर

From Vigyanwiki

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

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

यह उपकरण उन लैंग्वेज में विशेष रूप से प्रभावी और सुविधाजनक है जो लोकल फ़ंक्शन परिभाषाओं जैसे पास्कल और 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 और दो प्रक्रियात्मक पैरामीटर प्रीक, स्वैप लेता है:

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

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

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

उदाहरण के लिए, हम 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 से शुरू होते हैं। निम्नलिखित कोड प्रत्येक पंक्ति में तत्वों को पुनर्व्यवस्थित करेगा ताकि सभी सम मान सभी विषम मानों से पहले आएं:

'पूर्णांक' मैं
'प्रक्रिया' eoprec(r, s):
    'वापसी' (एम[आई, आर] 'मॉड' 2) < (एम[आई, एस] 'मॉड' 2);

'प्रक्रिया' ईओस्वैप(आर, एस):
    'पूर्णांक' टी;
    टी ← एम[आई,आर];
    एम[आई,आर] ← एम[आई,एस];
    एम[आई,एस] ← टी;

'के लिए' मैं 1 'से' 10 तक 'करता हूं'
    आइसोर्ट(1, 20, ईओप्रेक, ईओस्वैप);

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

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

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

'प्रक्रिया' वेक्सोर्ट(एन, वी, इंसीआर):

    'प्रक्रिया' vprec(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, इस प्रभाव को प्राप्त करने के लिए जटिल और/या थ्रेड सुरक्षा|थ्रेड-असुरक्षित कोड की आवश्यकता होगी।

उदाहरण: दो अनुक्रमों का विलय

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

'प्रक्रिया' मर्ज (ए, बी, सटीक, अगलाए, परिशिष्टए, अगलाबी, परिशिष्टबी):
    'पता' आईएनआई, फिन, टी
    ini ← Λ; फिन ← Λ
    'जबकि' A ≠ Λ या B ≠ Λ 'करें'
        'यदि' B = Λ 'या' (A ≠ Λ 'और' B ≠ Λ 'और' prec(A, B)) 'तब'
            t ← अगलाA(A)
            फिन ← परिशिष्टए(ए, फिन); 'अगर' आईएनआई = Λ 'तब' आईएनआई ← फिन
            ए ← टी
        'अन्य'
            t ← अगलाB(B)
            फिन ← एपेंडबी(बी, फिन); 'अगर' आईएनआई = Λ 'तब' आईएनआई ← फिन
            बी ← टी
    'वापसी' ini

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

लिंक की गई सूचियों का विलय

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

'प्रक्रिया' सूची मर्ज (आर, एस):

    'प्रक्रिया' पूर्व(आर, एस):
        'वापसी' r.INFO < s.INFO

    'प्रक्रिया' अगला(x):
        'वापसी' x.अगला

    'प्रक्रिया' परिशिष्ट (एक्स, फिन)
        'अगर' फिन ≠ Λ 'तो' फिन.अगला ← एक्स
        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 के बराबर है।

'प्रक्रिया' सरणीमर्ज (यू, एम, वी, एन, डब्ल्यू):

    'प्रक्रिया' पूर्व(आर, एस):
        'वापसी' (*r) > (*s)

    'प्रक्रिया' अगलाU(x):
        'अगर' x = &(U[m−1]) 'तो' 'वापसी' Λ 'अन्यथा' 'वापसी' x + 1

    'प्रक्रिया' अगलाV(x):
        'अगर' x = &(V[n−1]) 'तो' 'वापसी' Λ 'अन्यथा' 'वापसी' x + 1

    'प्रक्रिया' परिशिष्ट (एक्स, फिन)
        'if' fin = Λ 'then' fin ← &(W[0])
        (*फिन) ← (*x)
        'वापसी' फिन + 1
        
    'यदि' m = 0 तो U ← Λ
    'यदि' n = 0 तो V ← Λ
    'वापसी' मर्ज (यू, वी, प्रीक, नेक्स्टयू, अपेंड, नेक्स्टवी, अपेंड)

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

एक अंतराल पर एकीकृत करना

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

'प्रक्रिया' Intg(f, a, b, n):
    'फ्लोट' टी, एक्स, एस; 'पूर्णांक' मैं
    'अगर' बी = ए 'तो' 'वापसी' 0
    एक्स ← ए; 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
    'वापसी' (बी - ए) * एस / एन

डिस्क पर एकीकरण

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

निम्नलिखित कोड एक समीकरण के पक्षों को लागू करता है|दाहिने हाथ का सूत्र:

प्रक्रिया DiskIntg(g, xc, yc, R, n)

    प्रक्रिया gring(z):

        प्रक्रिया जीपोलर(टी):
            फ़्लोट x, y
            xxc + z * cos(t)
            yyc + z * sin(t)
            वापसी जी(एक्स, वाई)

        पूर्णांक mगोल(n*z/R)
        वापसी z * Intg(gpolar, 0, 2*π, m)

    वापसी इंटग(ग्रिंग, 0, आर, एन)

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

इतिहास

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

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

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

यह भी देखें


श्रेणी:सबरूटीन्स