समारोह संकेत, क्लोजर, और लैम्ब्डा


86

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

तो सी-स्टाइल फ़ंक्शन पॉइंटर्स मूल रूप से क्लोजर या लैम्ब्डा से अलग क्यों हैं? जहां तक ​​मैं बता सकता हूं कि इस तथ्य के साथ यह करना है कि फ़ंक्शन पॉइंटर अभी भी एक परिभाषित (नामित) फ़ंक्शन को इंगित करता है, जो फ़ंक्शन को गुमनाम रूप से परिभाषित करने के अभ्यास के विपरीत है।

किसी कार्य को दूसरे मामले में अधिक शक्तिशाली के रूप में क्यों देखा जा रहा है, जहां यह अनाम है, पहले की तुलना में जहां यह सिर्फ एक सामान्य, रोजमर्रा का कार्य है जिसे पारित किया जा रहा है?

कृपया बताएं कि दोनों की तुलना इतनी बारीकी से कैसे और क्यों कर रहा हूं।

धन्यवाद।

जवाबों:


108

एक लैम्ब्डा (या क्लोजर ) फंक्शन पॉइंटर और वैरिएबल दोनों को एनकैप्सुलेट करता है। यही कारण है, सी # में, आप कर सकते हैं:

int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
   return i < lessThan;
};

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

int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
   return i < lessThan;
};

lessThanTest(99); // returns true
lessThan = 10;
lessThanTest(99); // returns false

सी में, यह अवैध होगा:

BOOL (*lessThanTest)(int);
int lessThan = 100;

lessThanTest = &LessThan;

BOOL LessThan(int i) {
   return i < lessThan; // compile error - lessThan is not in scope
}

हालाँकि मैं एक फ़ंक्शन पॉइंटर को परिभाषित कर सकता हूँ जो 2 तर्क देता है:

int lessThan = 100;
BOOL (*lessThanTest)(int, int);

lessThanTest = &LessThan;
lessThanTest(99, lessThan); // returns true
lessThan = 10;
lessThanTest(100, lessThan); // returns false

BOOL LessThan(int i, int lessThan) {
   return i < lessThan;
}

लेकिन, अब मुझे इसका मूल्यांकन करने पर २ तर्क पास करने होंगे। अगर मैं इस फंक्शन पॉइंटर को किसी अन्य फंक्शन में पास करना चाहता हूं, जहां लोथन स्कोप नहीं है, तो मुझे या तो इसे चेन में प्रत्येक फंक्शन में पास करके, या फिर इसे ग्लोबल में प्रमोट करके मैन्युअल रूप से जीवित रखना होगा।

यद्यपि अधिकांश मुख्यधारा की भाषाएं जो बंद का समर्थन करती हैं, अनाम कार्यों का उपयोग करती हैं, उसके लिए कोई आवश्यकता नहीं है। आप गुमनाम कार्यों के बिना बंद हो सकते हैं, और बिना बंद किए अनाम कार्य कर सकते हैं।

सारांश: एक क्लोजर फ़ंक्शन पॉइंटर + कैप्चर किए गए चर का एक संयोजन है।


धन्यवाद, आपने वास्तव में अन्य लोगों के विचार को घर ले लिया है जहां पर पहुंचने की कोशिश कर रहे हैं।
कोई भी

आप शायद C के पुराने संस्करण का उपयोग कर रहे थे जब आपने इसे लिखा था या फ़ंक्शन को आगे घोषित करने के लिए याद नहीं किया था, लेकिन मैं उसी व्यवहार का निरीक्षण नहीं करता हूं जब आपने यह परीक्षण किया था। ideone.com/JsDVBK
smac89

@ smac89 - आपने कमटैन चर को एक वैश्विक बना दिया - मैंने स्पष्ट रूप से एक विकल्प के रूप में उल्लेख किया है।
मार्क ब्रैकेट

42

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

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

आप सी में यह सब अनुकरण कर सकते हैं, लेकिन यह गधे में दर्द है। दो तकनीकें लोकप्रिय हैं:

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

  2. एक पॉइंटर को एक संरचना में पास करें, जहां संरचना में मुक्त चर के मान शामिल हैं और कोड के लिए एक पॉइंटर भी है।

तकनीक # 1 आदर्श है जब आप C में किसी प्रकार के बहुरूपता का अनुकरण करने की कोशिश कर रहे हैं और आप पर्यावरण के प्रकार को प्रकट नहीं करना चाहते हैं --- आप पर्यावरण का प्रतिनिधित्व करने के लिए एक शून्य * पॉइंटर का उपयोग करते हैं। उदाहरण के लिए, डेव हैन्सन के सी इंटरफेस और कार्यान्वयन को देखें । तकनीक # 2, जो अधिक निकटता से मिलती-जुलती है, जो कार्यात्मक भाषाओं के लिए देशी-कोड संकलक में होती है, एक अन्य परिचित तकनीक से भी मिलती है ... C ++ आभासी सदस्य कार्यों के साथ। कार्यान्वयन लगभग समान हैं।

इस अवलोकन से हेनरी बेकर की समझदारी का मार्ग प्रशस्त हुआ:

अल्गोल / फोरट्रान दुनिया के लोगों ने वर्षों तक शिकायत की कि उन्हें समझ में नहीं आया कि भविष्य के कुशल प्रोग्रामिंग में संभावित उपयोग बंद होने का क्या होगा। तब nowobject ओरिएंटेड प्रोग्रामिंग 'क्रांति हुई, और अब सभी फ़ंक्शन फ़ंक्शन क्लोजर का उपयोग करते हैं, सिवाय इसके कि वे अभी भी उन्हें कॉल करने से इनकार करते हैं।


1
+1 स्पष्टीकरण और उद्धरण के लिए कि OOP वास्तव में बंद है - एक मौजूदा फ़ंक्शन का पुन: उपयोग करता है, लेकिन नए मुक्त चर के साथ ऐसा करता है - फ़ंक्शन (विधियाँ) जो पर्यावरण को लेते हैं (एक वस्तु को इंगित करने के लिए एक संरचनात्मक सूचक डेटा जो नए राज्यों के अलावा कुछ भी नहीं है) चालू करना।
लीजेंड 2k

8

C में आप फ़ंक्शन इनलाइन को परिभाषित नहीं कर सकते, इसलिए आप वास्तव में एक क्लोजर नहीं बना सकते। आप जो कुछ कर रहे हैं वह कुछ पूर्व-परिभाषित पद्धति के संदर्भ में हो रहा है। गुमनाम तरीकों / बंद का समर्थन करने वाली भाषाओं में, विधियों की परिभाषा बहुत अधिक लचीली है।

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

संपादित करें: एक उदाहरण जोड़ना (मैं Actionscript-ish सिंटैक्स का उपयोग करने जा रहा हूं क्योंकि अभी मेरे दिमाग में यही है):

कहते हैं कि आपके पास कुछ ऐसी विधि है जो किसी अन्य विधि को अपने तर्क के रूप में लेती है, लेकिन जब यह कहा जाता है तो उस पद्धति के लिए किसी भी पैरामीटर को पारित करने का एक तरीका प्रदान नहीं करता है? जैसे, कहते हैं, कुछ विधि जो आपके द्वारा पारित विधि को चलाने से पहले देरी का कारण बनती है (बेवकूफ उदाहरण, लेकिन मैं इसे सरल रखना चाहता हूं)।

function runLater(f:Function):Void {
  sleep(100);
  f();
}

अब कहते हैं कि आप उपयोगकर्ता को चलाने के लिए चाहते हैं () एक वस्तु के कुछ प्रसंस्करण में देरी करने के लिए:

function objectProcessor(o:Object):Void {
  /* Do something cool with the object! */
}

function process(o:Object):Void {
  runLater(function() { objectProcessor(o); });
}

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

मुझे उम्मीद है कि वह अर्थवान है।


मैंने आपकी टिप्पणी के आधार पर अपना उत्तर दिया। मैं अभी भी शर्तों की बारीकियों पर 100% स्पष्ट नहीं हूं, इसलिए मैंने आपको सीधे उद्धृत किया। :)
हरम

अनाम कार्यों की इनलाइन क्षमता (अधिकतर?) मुख्यधारा की प्रोग्रामिंग भाषाओं का कार्यान्वयन विवरण है - यह बंद करने की आवश्यकता नहीं है।
मार्क ब्रैकेट

6

समापन = तर्क + वातावरण।

उदाहरण के लिए, इस C # 3 विधि पर विचार करें:

public Person FindPerson(IEnumerable<Person> people, string name)
{
    return people.Where(person => person.Name == name);
}

लैम्ब्डा अभिव्यक्ति न केवल तर्क ("नाम की तुलना करें") को बल्कि पैरामीटर (यानी स्थानीय चर) "नाम" सहित पर्यावरण को भी कूटबद्ध करता है।

इस पर अधिक जानकारी के लिए, क्लोजर पर मेरे लेख पर एक नज़र डालें जो आपको C # 1, 2 और 3 के माध्यम से ले जाता है, जिसमें दिखाया गया है कि कैसे चीजें आसान होती हैं।


IEnumerable <व्यक्ति> के साथ शून्य की जगह पर विचार करें
एमी बी

1
@ डेविड बी: चीयर्स, किया। @edg: मुझे लगता है कि, बस राज्य से भी अधिक है, क्योंकि यह है परिवर्तनशील राज्य। दूसरे शब्दों में, यदि आप किसी क्लोजर को निष्पादित करते हैं जो एक स्थानीय वैरिएबल को बदलता है (जबकि अभी भी विधि के भीतर) तो वह स्थानीय वैरिएबल भी बदल जाता है। "पर्यावरण" मुझे इस बारे में बेहतर बताता है, लेकिन यह ऊनी है।
जॉन स्कीट

मैं उत्तर की सराहना करता हूं, लेकिन यह वास्तव में मेरे लिए कुछ भी स्पष्ट नहीं करता है, ऐसा लगता है कि लोग सिर्फ एक वस्तु हैं और इस पर आपका एक तरीका है। शायद यह सिर्फ मुझे पता नहीं है C #।
कोई भी

हां, यह इस पर एक विधि कह रहा है - लेकिन यह जिस पैरामीटर से गुजर रहा है वह बंद है।
जॉन स्कीट

4

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

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

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

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

लैम्ब्डा ( अनाम फ़ंक्शंस ) वास्तव में एक अलग मुद्दा है, लेकिन आमतौर पर एक भाषा जो आपको फ़ंक्शंस पर गुमनाम फ़ंक्शंस को परिभाषित करने देती है, आपको फ़ंक्शन फ़ंक्शन के रूप में उन्हें वापस करने देती है, इसलिए वे अंत में बंद हो रहे हैं।


3

एक लैम्ब्डा एक अनाम, गतिशील रूप से परिभाषित फ़ंक्शन है। आप सी में ऐसा नहीं कर सकते ... बंद करने के लिए के रूप में (या दो की सजा), विशिष्ट लिस्प उदाहरण कुछ की तर्ज पर दिखेगा:

(defun get-counter (n-start +-number)
     "Returns a function that returns a number incremented
      by +-number every time it is called"
    (lambda () (setf n-start (+ +-number n-start))))

सी के संदर्भ में, आप कह सकते हैं कि लेक्सिकल एनवायरनमेंट (स्टैक) get-counterको अनाम फ़ंक्शन द्वारा कैप्चर किया जा रहा है, और आंतरिक रूप से निम्न उदाहरण के रूप में संशोधित किया गया है:

[1]> (defun get-counter (n-start +-number)
         "Returns a function that returns a number incremented
          by +-number every time it is called"
        (lambda () (setf n-start (+ +-number n-start))))
GET-COUNTER
[2]> (defvar x (get-counter 2 3))
X
[3]> (funcall x)
5
[4]> (funcall x)
8
[5]> (funcall x)
11
[6]> (funcall x)
14
[7]> (funcall x)
17
[8]> (funcall x)
20
[9]> 

2

फ़ंक्शन परिभाषा के बिंदु से क्लोज़र कुछ चर का अर्थ फ़ंक्शन लॉजिक के साथ एक साथ बंधे होते हैं, जैसे कि मक्खी पर एक मिनी-ऑब्जेक्ट घोषित करने में सक्षम होना।

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

मैं लैम्ब्डा को क्लोजर से लैस करने में सहज नहीं हूं क्योंकि मुझे यकीन नहीं है कि सभी भाषाओं में लैम्बडा क्लोजर हैं, कई बार मुझे लगता है कि लैम्ब्डा को केवल वैरिएबल (पायथन प्री 2.1?) के बंधन के बिना स्थानीय रूप से परिभाषित अनाम फ़ंक्शन कहा गया है।


2

GCC में निम्नलिखित मैक्रो का उपयोग करके लैम्ब्डा कार्यों को अनुकरण करना संभव है:

#define lambda(l_ret_type, l_arguments, l_body)       \
({                                                    \
    l_ret_type l_anonymous_functions_name l_arguments \
    l_body                                            \
    &l_anonymous_functions_name;                      \
})

स्रोत से उदाहरण :

qsort (array, sizeof (array) / sizeof (array[0]), sizeof (array[0]),
     lambda (int, (const void *a, const void *b),
             {
               dump ();
               printf ("Comparison %d: %d and %d\n",
                       ++ comparison, *(const int *) a, *(const int *) b);
               return *(const int *) a - *(const int *) b;
             }));

निश्चित रूप से इस तकनीक का उपयोग अन्य संकलक के साथ काम करने वाले आपके आवेदन की संभावना को हटा देता है और जाहिर है "YMMV" अपरिभाषित है।


2

बंद कब्जा मुक्त चर एक में पर्यावरण । वातावरण अभी भी मौजूद रहेगा, भले ही आसपास का कोड सक्रिय न हो।

कॉमन लिस्प में एक उदाहरण है, जहां MAKE-ADDERएक नया बंद होता है।

CL-USER 53 > (defun make-adder (start delta) (lambda () (incf start delta)))
MAKE-ADDER

CL-USER 54 > (compile *)
MAKE-ADDER
NIL
NIL

उपरोक्त फ़ंक्शन का उपयोग करना:

CL-USER 55 > (let ((adder1 (make-adder 0 10))
                   (adder2 (make-adder 17 20)))
               (print (funcall adder1))
               (print (funcall adder1))
               (print (funcall adder1))
               (print (funcall adder1))
               (print (funcall adder2))
               (print (funcall adder2))
               (print (funcall adder2))
               (print (funcall adder1))
               (print (funcall adder1))
               (describe adder1)
               (describe adder2)
               (values))

10 
20 
30 
40 
37 
57 
77 
50 
60 
#<Closure 1 subfunction of MAKE-ADDER 4060001ED4> is a CLOSURE
Function         #<Function 1 subfunction of MAKE-ADDER 4060001CAC>
Environment      #(60 10)
#<Closure 1 subfunction of MAKE-ADDER 4060001EFC> is a CLOSURE
Function         #<Function 1 subfunction of MAKE-ADDER 4060001CAC>
Environment      #(77 20)

ध्यान दें कि DESCRIBEफ़ंक्शन दर्शाता है कि दोनों क्लोजर के लिए फ़ंक्शन ऑब्जेक्ट समान हैं, लेकिन पर्यावरण अलग है।

कॉमन लिस्प क्लोजर और शुद्ध फंक्शन ऑब्जेक्ट्स (बिना पर्यावरण वाले) दोनों को कार्य करता है और दोनों को एक ही तरीके से कॉल कर सकते हैं, यहां उपयोग कर रहे हैं FUNCALL


1

C में लेक्सिकल स्कूपिंग की कमी से मुख्य अंतर उत्पन्न होता है।

एक फंक्शन पॉइंटर सिर्फ वो होता है, जो पॉइंटर कोड के ब्लॉक में होता है। कोई भी गैर-स्टैक चर जिसे यह संदर्भित करता है वह वैश्विक, स्थिर या समान है।

एक बंद, OTOH, 'बाहरी चर', या 'upvalues' के रूप में अपनी स्थिति है। वे निजी या साझा किए जा सकते हैं जैसा आप चाहते हैं, लेक्सिकल स्कूपिंग का उपयोग कर सकते हैं। आप समान फ़ंक्शन कोड के साथ बहुत सारे क्लोजर बना सकते हैं, लेकिन विभिन्न चर उदाहरण।

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

संक्षेप में, एक क्लोजर एक फ़ंक्शन पॉइंटर है जो कुछ राज्य है। यह एक उच्च-स्तरीय निर्माण है


2
WTF? सी निश्चित रूप से लेक्सिकल स्कूपिंग है।
लुइसे ओलिवेरा

1
इसमें 'स्टेटिक स्कूपिंग' है। जैसा कि मैंने इसे समझा है, लेक्सिकल स्कूपिंग एक ऐसी भाषा पर समान शब्दार्थ बनाए रखने के लिए एक अधिक जटिल विशेषता है जिसमें गतिशील रूप से बनाए गए कार्य हैं, जिन्हें तब क्लोजर कहा जाता है।
जेवियर

1

अधिकांश प्रतिक्रियाओं से संकेत मिलता है कि क्लोजर को फ़ंक्शन पॉइंटर्स की आवश्यकता होती है, संभवतः अनाम फ़ंक्शन के लिए, लेकिन जैसा कि मार्क ने लिखा क्लोजर नामित कार्यों के साथ मौजूद हो सकते हैं। यहाँ पर्ल में एक उदाहरण है:

{
    my $count;
    sub increment { return $count++ }
}

क्लोजर वह वातावरण है जो $countचर को परिभाषित करता है । यह केवल incrementसबरूटिन के लिए उपलब्ध है और कॉल के बीच बनी रहती है।


0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.