नेस्टेड फ़ंक्शन

From Vigyanwiki
Revision as of 18:20, 4 August 2023 by alpha>Sangeeta

कंप्यूटर प्रोग्रामिंग में, नेस्टेड फलन (या नेस्टेड प्रक्रिया या सबरूटीन) सबरूटीन होता है, जिसे किसी अन्य फलन, एनक्लोजिंग फलन के अंदर परिभाषित किया जाता है। सरल पुनरावर्ती सीमा (प्रोग्रामिंग) नियमों के कारण, नेस्टेड फलन अपने तत्काल संलग्न फलन के बाहर अदृश्य होता है, किन्तु अपने तत्काल संलग्न फलन के साथ-साथ किसी भी फलन के सभी स्थानीय वस्तु (कंप्यूटर विज्ञान) (डेटा, फलन, प्रकार इत्यादि) को देख (पहुंच) सकता है, जो परिवर्तन में, उस फलन को संलग्न करता है। नेस्टिंग सैद्धांतिक रूप से असीमित सघन तक संभव है, चूंकि व्यावहारिक कार्यक्रमों में सामान्यतः केवल कुछ स्तरों का उपयोग किया जाता है।

नेस्टेड फलन का उपयोग संरचित प्रोग्रामिंग के कई दृष्टिकोणों में किया जाता है, जिनमें प्रारंभिक फलन भी सम्मिलित हैं, जैसे कि ALGOL, 67 से और पास्कल (प्रोग्रामिंग भाषा), और कई आधुनिक गतिशील भाषाओं और कार्यात्मक भाषाओं में भी चूंकि, वे पारंपरिक रूप से भाषाओं के (मूल रूप से सरल) सी-परिवार में समर्थित नहीं हैं।

प्रभाव

नेस्टेड फलन कार्य क्षेत्र या ब्लॉक का सीमा मानते हैं। नेस्टेड फलन का सीमा एन्क्लोजिंग फलन के अंदर होता है, यानी उस फलन के घटक ब्लॉकों में से के अंदर, जिसका अर्थ है कि यह उस ब्लॉक के बाहर और एन्क्लोजिंग फलन के बाहर भी अदृश्य है। नेस्टेड फलन अन्य स्थानीय फलन, वेरिएबल्स, स्थिरांक, प्रकार, वर्ग इत्यादि तक पहुंच सकता है जो समान दायरे में हैं, या किसी भी संलग्न दायरे में, स्पष्ट पैरामीटर पास किए बिना, जो नेस्टेड फलन के अंदर और बाहर डेटा पास करने को बहुत सरल बनाता है। इसे आम तौर पर पढ़ने और लिखने दोनों के लिए अनुमति दी जाती है।

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

उदाहरण

पास्कल सिंटैक्स का उपयोग करने वाला उदाहरण (ALGOL, Modula 2, ओबेरॉन (प्रोग्रामिंग भाषा), Ada (प्रोग्रामिंग भाषा), आदि के साथ समान):

function E(x: real): real;
    function F(y: real): real;
    begin
        F := x + y
    end;
begin
    E := F(3) + F(4)
end;

कार्यक्रम F अंदर निहित है E. ध्यान दें कि Eका पैरामीटर x में भी दिखाई देता है F (जैसा F का यह है E) जबकि दोनों x और y बाहर अदृश्य हैं E और F क्रमश।

इसी प्रकार, मानक एमएल में:

fun e (x : real) =
  let
    fun f y = x+y
  in
    f 3 + f 4
  end;

हास्केल (प्रोग्रामिंग भाषा) सिंटैक्स में ही उदाहरण लिखने का तरीका:

e :: Float -> Float
e x = f 3 + f 4 where f y = x + y

जीएनयू कंपाइलर संग्रह सिंटैक्स में भी यही उदाहरण है[1] (सी नेस्टेड फलन के साथ विस्तारित):

float E(float x)
{
    float F(float y)
    {
        return x + y;
    }
    return F(3) + F(4);
}

जल्दी से सुलझाएं

अधिक यथार्थवादी उदाहरण क्विकसॉर्ट का यह कार्यान्वयन है:[2]

void sort(int *items, int size) {
    void quickSort(int first, int last) {
        void swap(int p, int q) {
            int tmp = items[p];
            items[p] = items[q];
            items[q] = tmp;
        }
        
        int partition() {
            int pivot = items[first], index = first;
            swap(index, last);
            for (int i = first; i < last; i++)
                if (items[i] < pivot)
                    swap(index++, i);
            swap(index, last);
            return index;
        }

        if (first < last) {
            int pivotIndex = partition();
            quickSort(first, pivotIndex - 1);
            quickSort(pivotIndex + 1, last);
        }
    }
    quickSort(0, size - 1);
}

अन्य उदाहरण C++11#Lambda फलन और अभिव्यक्तियों का उपयोग करके क्विकॉर्ट#होरे विभाजन योजना का निम्नलिखित कार्यान्वयन है|C++11 Anonymous function#C.2B.2B .28चूंकि C.2B.2B11.29: <सिंटैक्सहाइलाइट लैंग=सी++> टेम्पलेट<टाइपनाम RandomAccessIterator> ऑटो सॉर्ट (RandomAccessIterator प्रारंभ, RandomAccessIterator अंत)->शून्य { स्वतः विभाजन = [&]() { //होरे विभाजन योजना ऑटो &पिवोट = *आरंभ; ऑटो फॉरवर्ड कर्सर = आरंभ; ऑटो बैकवर्ड कर्सर = अंत - 1; ऑटो पार्टिशनपोजीशनफाउंड = गलत; ऑटो लोकेटपार्टीशनपोजीशन = [&]() { जबकि (*फॉरवर्डकर्सर <पिवोट) ++फॉरवर्डकर्सर; जबकि (पिवोट < *बैकवर्ड कर्सर) --बैकवर्डकर्सर; यदि (फॉरवर्ड कर्सर >= बैकवर्ड कर्सर) पार्टिशनपोज़िशनफ़ाउंड = सत्य; अन्य स्वैप (*फॉरवर्डकर्सर, *बैकवर्डकर्सर); }; //तुच्छ सहायक कार्य ऑटो MoveOnAndTryAgain = [&]() { ++फॉरवर्डकर्सर; --बैकवर्डकर्सर; }; //वास्तविक विभाजन प्रक्रिया की संक्षिप्त रूपरेखा जबकि (सत्य) { LoatePartitionPosition(); यदि (विभाजनस्थिति मिली) बैकवर्डकर्सर + 1 लौटाएँ; अन्य MoveOnAndTryAgain(); } }; // क्विकसॉर्ट एल्गोरिदम की संक्षिप्त रूपरेखा यदि (प्रारंभ <अंत - 1) { स्वतः विभाजन स्थिति = विभाजन(); सॉर्ट करें (प्रारंभ, विभाजन स्थिति); सॉर्ट करें (विभाजन स्थिति, अंत); } } </सिंटैक्सहाइलाइट>

उद्देश्य

लेक्सिकली नेस्टेड फलन परिभाषाएँ जानकारी छिपाने का रूप हैं और प्रक्रियात्मक कार्यों को उप-कार्यों में विभाजित करने के लिए उपयोगी हैं जो केवल स्थानीय रूप से सार्थक हैं। यह प्रोग्राम के अन्य हिस्सों को उन कार्यों और चरों से अव्यवस्थित होने से बचाता है जो उन हिस्सों से असंबंधित हैं।

इन्हें आम तौर पर आवरण समारोह के रूप में या किसी अन्य फलन के अंदर रिकर्सन (कंप्यूटर विज्ञान) के रूप में उपयोग किया जाता है (जैसा कि ऊपर दिए गए क्विकसॉर्ट उदाहरण में है)। इससे कोड को व्यवस्थित करने का संरचनात्मक लाभ होता है, दायरे को प्रदूषित होने से बचाया जाता है, और कार्यों को आसानी से स्थिति साझा करने की भी अनुमति मिलती है।[3] चूंकि नेस्टेड फलन एनक्लोजिंग फलन के स्थानीय वेरिएबल्स तक पहुंच सकता है, इसलिए नेस्टेड फलन के पैरामीटर्स को पास किए बिना या वैश्विक वेरिएबल का उपयोग किए बिना, कोड को सरल बनाकर राज्य को साझा करना संभव है।

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

अन्य उपयोग

प्रवाह नियंत्रित करें

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

उच्च-क्रम के कार्य

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

विकल्प

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

अन्य विकल्प फलन मापदंडों के माध्यम से कार्यों के बीच स्थिति को साझा करना है, प्रतिलिपि की लागत से बचने के लिए अक्सर संदर्भों को तर्क के रूप में पारित करना। सी में इसे आम तौर पर सूचक द्वारा संदर्भ वाली संरचना में कार्यान्वित किया जाता है।[4]इससे फलन कॉल की जटिलता काफी बढ़ जाती है।[3]

PHP और अन्य भाषाओं में अनाम फलन ही मात्र विकल्प है: नेस्टेड फलन को सामान्य फलन के रूप में नहीं, बल्कि संदर्भ द्वारा, स्थानीय चर के रूप में घोषित किया जाता है। अनाम फलन में स्थानीय चर का उपयोग करने के लिए, क्लोजर (कंप्यूटर विज्ञान) का उपयोग करें।

भाषाएँ

लेक्सिकली नेस्टेड फलन का समर्थन करने वाली प्रसिद्ध भाषाओं में सम्मिलित हैं:

कार्यात्मक भाषाएँ

अधिकांश कार्यात्मक प्रोग्रामिंग भाषाओं में, जैसे कि स्कीम, नेस्टेड फलन लूप के साथ कलन विधि लागू करने का प्रोग्रामिंग मुहावरा है। सरल (टेल प्रत्यावर्तन ) रिकर्सन आंतरिक फलन बनाया जाता है, जो एल्गोरिदम के मुख्य लूप के रूप में व्यवहार करता है, जबकि बाहरी फलन स्टार्टअप क्रियाएं करता है जिन्हें केवल बार करने की आवश्यकता होती है। अधिक जटिल मामलों में, कई पूँछ प्रत्यावर्तन कार्यों को आंतरिक कार्यों के रूप में बनाया जा सकता है।

प्रत्यक्ष समर्थन के बिना कुछ भाषाएँ

कुछ भाषाओं में नेस्टेड फलन को लागू करने के लिए सीधा वाक्यविन्यास और अर्थ संबंधी समर्थन नहीं होता है। फिर भी, उनमें से कुछ के लिए नेस्टेड फलन के विचार को अन्य भाषा निर्माणों के उपयोग के माध्यम से कुछ हद तक कठिनाई के साथ अनुकरण किया जा सकता है। निम्नलिखित भाषाएँ संबंधित रणनीतियों के माध्यम से नेस्टेड कार्यों का अनुमान लगा सकती हैं:

  • सी++
    • सी++11 से पहले: कक्षाओं के अंदर कक्षाओं की परिभाषा की अनुमति देता है, स्तर में नेस्टेड फलन के समान क्लास विधियों का उपयोग करने की क्षमता प्रदान करता है (फलन वस्तु#सी में और सी.2बी.2बी|सी++ में फलन वस्तु देखें)।
    • C++11 के बाद से: उपरोक्त क्विकसॉर्ट उदाहरण के रूप में लैम्ब्डा ्सप्रेशन का उपयोग करके।[9]
  • एफिल (प्रोग्रामिंग भाषा) स्पष्ट रूप से रूटीन के नेस्टिंग की अनुमति नहीं देता है। यह भाषा को सरल बनाए रखने के लिए है, और (मूल्य-रिटर्निंग) फलन के परिणाम को दर्शाने के लिए विशेष चर, परिणाम का उपयोग करने की परंपरा को भी अनुमति देता है।
  • विज़ुअल बेसिक .NET, अनाम तरीकों या लैम्ब्डा ्सप्रेशन का उपयोग करके।
  • जावा (प्रोग्रामिंग भाषा), लैम्ब्डा अभिव्यक्तियों का उपयोग करके[10] (अनाम फलन#जावा देखें) (जावा 8 के बाद से) या वर्कअराउंड के माध्यम से जिसमें अनाम वर्ग होता है जिसमें ही विधि होती है। किसी विधि के लिए स्थानीय घोषित नामित वर्ग का भी उपयोग किया जा सकता है।

कार्यान्वयन

नेस्टेड फलन का कार्यान्वयन जितना दिखाई दे सकता है उससे कहीं अधिक सम्मिलित हो सकता है, नेस्टेड फलन के संदर्भ के रूप में जो गैर-स्थानीय चर का संदर्भ देता है वह क्लोजर (कंप्यूटर विज्ञान) बनाता है। इस कारण से नेस्टेड फलन कुछ भाषाओं जैसे C, C++ या Java में समर्थित नहीं हैं क्योंकि इससे कंपाइलर्स को लागू करना अधिक कठिन हो जाता है।[4][11] चूंकि, कुछ कंपाइलर कंपाइलर विशिष्ट ्सटेंशन के रूप में उनका समर्थन करते हैं। इसका प्रसिद्ध उदाहरण सी का जीएनयू सी कार्यान्वयन है जो पास्कल, एडा और मोडुला जैसी भाषाओं के लिए कंपाइलरों के साथ कोड साझा करता है।

गैर-स्थानीय वस्तुओं तक पहुंच

शाब्दिक रूप से सीमित भाषा में नेस्टेड प्रक्रियाओं को लागू करने के कई तरीके हैं, किन्तु क्लासिक तरीका इस प्रकार है:

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

यह मूल विधि जितनी प्रतीत होती है उससे अधिक तेज़ है, किन्तु फिर भी इसे अक्सर व्यावहारिक आधुनिक कंपाइलरों (कॉल स्टैक#डिस्प्ले या इसी तरह की तकनीकों का उपयोग करके) में अनुकूलित किया जाता है।

नेस्टेड फलन को कार्यान्वित करने का और तरीका जो कुछ कंपाइलर्स द्वारा उपयोग किया जाता है वह है (लिफ्ट) नेस्टेड फलन को गैर-नेस्टेड फलन में परिवर्तित करना (जहां अतिरिक्त, छिपे हुए, पैरामीटर ्सेस लिंक को प्रतिस्थापित करते हैं) संकलन में मध्यवर्ती चरण के दौरान लैम्ब्डा उठाना के रूप में ज्ञात प्रक्रिया का उपयोग करते हुए।

मूल्यों के रूप में कार्य

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

नहीं-निष्पादित स्टैक

नेस्टेड फलन के कम से कम कार्यान्वयन से NX बिट|नो-्ज़ीक्यूट स्टैक (NX स्टैक) का नुकसान होता है। जीसीसी का नेस्टेड फलन कार्यान्वयन रनटाइम पर मशीन स्टैक में डाले गए जंप निर्देश के माध्यम से नेस्टेड फलन को कॉल करता है। इसके लिए स्टैक का निष्पादन योग्य होना आवश्यक है।

जीसीसी के तहत कोई भी निष्पादन स्टैक और नेस्टेड फलन परस्पर अनन्य नहीं हैं। यदि किसी प्रोग्राम के विकास में नेस्टेड फलन का उपयोग किया जाता है, तो एन्स स्टैक चुपचाप खो जाता है। जीसीसी ऑफर करता है -Wtrampoline स्थिति के प्रति सचेत करने की चेतावनी।

सॉफ्टवेयर विकास सुरक्षा का उपयोग करके इंजीनियर किए गए सॉफ़्टवेयर अक्सर NX स्टैक के नुकसान के कारण इस विशेष कंपाइलर (GCC) में नेस्टेड फलन के उपयोग की अनुमति नहीं देते हैं।[13]

यह भी देखें

संदर्भ

  1. Rothwell, Trevis J. (2011). जीएनयू सी संदर्भ मैनुअल. Free Software Foundation, Inc. p. 63.
  2. Re: Nesting functions- Why?, baavgai, 14 January 2012
  3. 3.0 3.1 Bright 2004.
  4. 4.0 4.1 4.2 "Question 20.24: Why doesn't C have nested functions?, comp.lang.c FAQ
  5. "A tour of the Dart language".
  6. "Functions | Kotlin".
  7. "Nested Methods".
  8. "Nested Functions – Using the GNU Compiler Collection (GCC)". GNU Project. Retrieved 2007-01-06.
  9. "Nested function - Rosetta Code".
  10. "Nested function - Rosetta Code".
  11. answer by Dave Vandervies, Aug 28 '09 at 17:45, to "Why are nested functions not supported by the C standard?"
  12. Such a combination of function code and its environment is sometimes called a closure.
  13. Walton, Jeffrey. "C-Based Toolchain Hardening". The Open Web Application Security Project (OWASP). Retrieved 28 February 2017.


बाहरी संबंध