कोई समझा सकता है? मैं उनके पीछे की मूल अवधारणाओं को समझता हूं, लेकिन मैं अक्सर उन्हें परस्पर उपयोग करते हुए देखता हूं और मैं भ्रमित हो जाता हूं।
और अब जब हम यहाँ हैं, तो वे एक नियमित कार्य से कैसे भिन्न हैं?
कोई समझा सकता है? मैं उनके पीछे की मूल अवधारणाओं को समझता हूं, लेकिन मैं अक्सर उन्हें परस्पर उपयोग करते हुए देखता हूं और मैं भ्रमित हो जाता हूं।
और अब जब हम यहाँ हैं, तो वे एक नियमित कार्य से कैसे भिन्न हैं?
जवाबों:
एक लंबोदर सिर्फ एक अनाम फ़ंक्शन है - एक फ़ंक्शन जिसे बिना किसी नाम से परिभाषित किया गया है। कुछ भाषाओं में, जैसे कि योजना, वे नामित कार्यों के समतुल्य हैं। वास्तव में, फंक्शन डेफिनिशन को एक लैम्बडा को एक वैरिएबल में आंतरिक रूप से बांधने के रूप में फिर से लिखा जाता है। अन्य भाषाओं में, पायथन की तरह, उनके बीच कुछ (बल्कि अनावश्यक) अंतर हैं, लेकिन वे अन्यथा उसी तरह व्यवहार करते हैं।
एक बंद कोई भी फ़ंक्शन है जो उस वातावरण पर बंद हो जाता है जिसमें इसे परिभाषित किया गया था। इसका अर्थ है कि यह चर को अपनी पैरामीटर सूची में नहीं पहुँचा सकता है। उदाहरण:
def func(): return h
def anotherfunc(h):
return func()
यह एक त्रुटि का कारण होगा, क्योंकि पर्यावरण में बंदfunc
नहीं होता है - अपरिभाषित है। केवल वैश्विक पर्यावरण पर बंद हो जाता है। यह काम करेगा:anotherfunc
h
func
def anotherfunc(h):
def func(): return h
return func()
क्योंकि यहाँ, func
में परिभाषित किया गया है anotherfunc
और अजगर 2.3 और अधिक में (या इस तरह कुछ संख्या) जब वे लगभग सही बंद हो गया (उत्परिवर्तन अभी भी काम नहीं करता है), इसका मतलब है कि यह पर्यावरण पर बंद हो जाता anotherfunc
है और अंदर चर तक पहुंच सकता है यह। पायथन 3.1+ में, कीवर्ड का उपयोग करतेnonlocal
समय म्यूटेशन भी काम करता है ।
एक और महत्वपूर्ण बिंदु - जब तक इसका मूल्यांकन नहीं किया जा रहा है तब भी यह पर्यावरण के func
ऊपर बंद होता रहेगा । यह कोड भी काम करेगा:anotherfunc
anotherfunc
def anotherfunc(h):
def func(): return h
return func
print anotherfunc(10)()
यह 10 छपेगा।
यह, जैसा कि आप नोटिस करते हैं, लैम्बडा एस के साथ कोई लेना-देना नहीं है - वे दो अलग-अलग (हालांकि संबंधित) अवधारणाएं हैं।
लैम्ब्डा और क्लोजर के आसपास बहुत भ्रम है, यहां तक कि इस स्टैकऑवरफ्लो प्रश्न के उत्तर में भी। यादृच्छिक प्रोग्रामर से पूछने के बजाय जिन्होंने कुछ प्रोग्रामिंग भाषाओं या अन्य क्लूलेस प्रोग्रामर के साथ अभ्यास से बंद होने के बारे में सीखा, स्रोत (जहां यह सब शुरू हुआ) की यात्रा करें। और चूंकि लैम्ब्डा और क्लोजर अलोंजो चर्च द्वारा आविष्कार किए गए लैम्ब्डा कैलकुलस से आते हैं , इसलिए 30 के दशक में पहले इलेक्ट्रॉनिक कंप्यूटर भी मौजूद थे, यही वह स्रोत है जिसके बारे में मैं बात कर रहा हूं।
लैम्ब्डा कैलकुलस दुनिया की सबसे सरल प्रोग्रामिंग भाषा है। केवल एक चीज जो आप इसमें कर सकते हैं: do
f x
। f
है और x
इसका एकमात्र पैरामीटर है)λ
(लैम्ब्डा), फिर प्रतीकात्मक नाम (उदाहरण x
), फिर .
अभिव्यक्ति से पहले एक बिंदु को जोड़कर किया जाता है। यह तब एक पैरामीटर की अपेक्षा फ़ंक्शन को अभिव्यक्ति में परिवर्तित करता है । उदाहरण के लिए: अभिव्यक्ति लेता है और बताता है कि इस अभिव्यक्ति में प्रतीक एक बाध्य चर है - यह एक मान के साथ प्रतिस्थापित किया जा सकता है जिसे आप एक पैरामीटर के रूप में आपूर्ति करते हैं।
ध्यान दें कि फ़ंक्शन इस तरह परिभाषित किया गया है अनाम हैλx.x+2
x+2
x
(λx.x+2) 7
। तब अभिव्यक्ति (इस मामले में एक शाब्दिक मूल्य) 7
को लागू लैम्ब्डा x
के उप- रूप में प्रतिस्थापित किया जाता है x+2
, इसलिए आपको प्राप्त होता है 7+2
, जो तब 9
सामान्य अंकगणितीय नियमों द्वारा कम हो जाता है।इसलिए हम रहस्यों में से एक समाधान कर लिया है:
लैम्ब्डा है गुमनाम समारोह , ऊपर के उदाहरण से λx.x+2
।
function(x) { return x+2; }
और आप इसे इस तरह से कुछ पैरामीटर पर तुरंत लागू कर सकते हैं:
(function(x) { return x+2; })(7)
या आप इस अनाम फ़ंक्शन (लैम्बडा) को कुछ चर में स्टोर कर सकते हैं:
var f = function(x) { return x+2; }
जो प्रभावी रूप से इसे एक नाम देता है f
, जिससे आप इसे संदर्भित कर सकते हैं और बाद में कई बार कॉल कर सकते हैं, जैसे:
alert( f(7) + f(10) ); // should print 21 in the message box
लेकिन आपको इसे नाम नहीं देना था। आप इसे तुरंत कॉल कर सकते हैं:
alert( function(x) { return x+2; } (7) ); // should print 9 in the message box
LISP में, लंबोदर इस तरह से बनाए जाते हैं:
(lambda (x) (+ x 2))
और आप ऐसे लैम्बडा को तुरंत एक पैरामीटर पर लागू करके कॉल कर सकते हैं:
( (lambda (x) (+ x 2)) 7 )
जैसा कि मैंने कहा, क्या लैम्ब्डा अमूर्त करता है बाध्यकारी अपने उपसूचक में एक प्रतीक है, इसलिए है कि यह एक substitutible हो जाता है पैरामीटर । इस तरह के प्रतीक को बाध्य कहा जाता है । लेकिन क्या होगा अगर अभिव्यक्ति में अन्य प्रतीक हैं? उदाहरण के लिए λx.x/y+2
:। इस अभिव्यक्ति में, प्रतीक x
लैंबडा एब्स्ट्रैक्शन से λx.
पहले से बंधा हुआ है। लेकिन दूसरा प्रतीक, y
बाध्य नहीं है - यह मुफ़्त है । हम नहीं जानते कि यह क्या है और यह कहां से आता है, इसलिए हम यह नहीं जानते कि इसका क्या अर्थ है और यह किस मूल्य का प्रतिनिधित्व करता है, और इसलिए हम उस अभिव्यक्ति का मूल्यांकन नहीं कर सकते जब तक कि हम y
इसका क्या मतलब निकालते हैं ।
वास्तव में, वही अन्य दो प्रतीकों के साथ जाता है, 2
और +
। यह सिर्फ इतना है कि हम इन दो प्रतीकों से इतने परिचित हैं कि हम आमतौर पर भूल जाते हैं कि कंप्यूटर उन्हें नहीं जानता है और हमें यह बताने की आवश्यकता है कि उन्हें कहीं और परिभाषित करने का क्या मतलब है, जैसे कि एक पुस्तकालय या भाषा में।
आप मुक्त प्रतीकों के बारे में सोच सकते हैं कि कहीं और, अभिव्यक्ति के बाहर, इसके "आसपास के संदर्भ" में, जिसे इसके पर्यावरण कहा जाता है । पर्यावरण एक बड़ी अभिव्यक्ति हो सकती है कि यह अभिव्यक्ति का एक हिस्सा है (जैसा कि क्यूई-गोन जिन ने कहा: "हमेशा एक बड़ी मछली होती है";)), या कुछ पुस्तकालय में, या भाषा में ही (एक आदिम के रूप में )।
इससे हम लैम्ब्डा के भावों को दो श्रेणियों में विभाजित कर सकते हैं:
आप पर्यावरण की आपूर्ति करके एक खुली मेमने की अभिव्यक्ति को बंद कर सकते हैं , जो इन सभी मुक्त प्रतीकों को कुछ मूल्यों (जो संख्या, तार, अनाम फ़ंक्शन उर्फ लंबोदा, जो भी हो ...) से बांधकर परिभाषित कर सकते हैं।
और यहाँ आता है बंद हिस्सा: बंद एक की लैम्ब्डा अभिव्यक्ति बाहरी संदर्भ (पर्यावरण) है कि करने के लिए मान देना में परिभाषित प्रतीकों के इस विशेष सेट है मुक्त प्रतीकों इस अभिव्यक्ति में, अब और उन्हें गैर मुक्त बना रही है। यह एक खुली मेमने की अभिव्यक्ति को बदल देता है , जिसमें अभी भी कुछ "अपरिभाषित" मुक्त प्रतीक शामिल हैं, एक बंद में , जिसमें अब कोई भी मुफ्त प्रतीक नहीं है।
उदाहरण के लिए, यदि आप निम्नलिखित लैम्ब्डा अभिव्यक्ति है: λx.x/y+2
, प्रतीक x
, स्वाभाविक है, जबकि प्रतीक y
नि: शुल्क है, इसलिए अभिव्यक्ति है open
और मूल्यांकन नहीं किया जा सकता जब तक कि आप कहते हैं कि क्या y
अर्थ है (और साथ ही +
और 2
है, जो भी स्वतंत्र हैं)। लेकिन मान लीजिए कि आपके पास भी ऐसा माहौल है:
{ y: 3,
+: [built-in addition],
2: [built-in number],
q: 42,
w: 5 }
यह पर्यावरण के लिए सभी "अपरिभाषित" (मुक्त) हमारे लैम्ब्डा अभिव्यक्ति से प्रतीकों के लिए आपूर्ति परिभाषाओं ( y
, +
, 2
), और कई अतिरिक्त प्रतीकों ( q
, w
)। जिन प्रतीकों को हमें परिभाषित करने की आवश्यकता है, वे पर्यावरण के सबसेट हैं:
{ y: 3,
+: [built-in addition],
2: [built-in number] }
और यह ठीक हमारे लैम्ब्डा अभिव्यक्ति का समापन है:>
दूसरे शब्दों में, यह एक खुली मेमने की अभिव्यक्ति को बंद कर देता है । यह वह जगह है जहां पहली बार नाम बंद हुआ था, और यही कारण है कि इस धागे में इतने सारे लोगों के जवाब बहुत सही नहीं हैं: पी
ठीक है, सन / ओरेकल, माइक्रोसॉफ्ट, गूगल आदि के कॉर्पोरेट बाज़ार को दोष देना है, क्योंकि यही उन्होंने अपनी भाषाओं (जावा, सी #, गो आदि) में इन निर्माणों को कहा है। वे अक्सर "क्लोजर" कहते हैं जो कि केवल लंबोदर माना जाता है। या वे एक विशेष तकनीक को "क्लोजर" कहते हैं जिसका उपयोग वे लेक्सिकल स्कूपिंग को लागू करने के लिए करते थे, अर्थात्, यह तथ्य कि एक फ़ंक्शन वैरिएबल तक पहुंच सकता है जिसे इसकी परिभाषा के समय इसके बाहरी दायरे में परिभाषित किया गया था। वे अक्सर कहते हैं कि फ़ंक्शन इन चरों को "घेरता है", जो बाहरी फ़ंक्शन के पूरा होने के बाद उन्हें नष्ट होने से बचाने के लिए उन्हें कुछ डेटा संरचना में कैप्चर करता है। लेकिन यह सिर्फ बनावटी पोस्ट फैक्टम "लोकगीत व्युत्पत्ति" और विपणन है, जो केवल चीजों को और अधिक भ्रमित करता है,
और यह इस तथ्य के कारण भी बदतर है कि वे जो कहते हैं, उसमें हमेशा थोड़ी सच्चाई होती है, जो आपको इसे झूठे रूप में आसानी से खारिज करने की अनुमति नहीं देता है: पी मुझे समझाएं:
यदि आप लैम्बदास का उपयोग करने वाली भाषा को प्रथम श्रेणी के नागरिकों के रूप में लागू करना चाहते हैं, तो आपको उन्हें अपने आस-पास के संदर्भ में परिभाषित प्रतीकों (जो आपके लैम्ब्डा में मुफ्त चर का उपयोग करना है) का उपयोग करने की अनुमति देने की आवश्यकता है। और ये प्रतीक तब भी होना चाहिए जब आसपास का फ़ंक्शन वापस आ जाए। समस्या यह है कि ये प्रतीक फ़ंक्शन के कुछ स्थानीय भंडारण (आमतौर पर कॉल स्टैक पर) से बंधे होते हैं, जो फ़ंक्शन के वापस आने पर अब और नहीं होगा। इसलिए, एक लैम्ब्डा के लिए जिस तरह से आप उम्मीद करते हैं, उसे काम करने के लिए, आपको किसी भी तरह से इन सभी मुक्त चर को अपने बाहरी संदर्भ से "कैप्चर" करने की आवश्यकता है और बाद में भी बाहरी संदर्भ के चले जाने पर उन्हें बचाएंगे। यही है, आपको क्लोजर खोजने की आवश्यकता हैआपके लैम्ब्डा (इन सभी बाहरी वेरिएबल्स का उपयोग करता है) और इसे कहीं और स्टोर करें (या तो कॉपी बनाकर, या उनके लिए जगह तैयार करके, स्टैक पर कहीं और)। इस लक्ष्य को प्राप्त करने के लिए आप जिस वास्तविक विधि का उपयोग करते हैं, वह आपकी भाषा का "कार्यान्वयन विवरण" है। यहां जो महत्वपूर्ण है, वह बंद है , जो आपके लंबो के वातावरण से मुक्त चर का सेट है जिसे कहीं न कहीं सहेजने की आवश्यकता है।
लोगों को वास्तविक डेटा संरचना को कॉल करना शुरू करने में बहुत समय नहीं लगा, जो वे अपनी भाषा के कार्यान्वयन में उपयोग करने के लिए क्लोजर "बंद" के रूप में लागू करते हैं। संरचना आमतौर पर कुछ इस तरह दिखती है:
Closure {
[pointer to the lambda function's machine code],
[pointer to the lambda function's environment]
}
और इन डेटा संरचनाओं को अन्य कार्यों के मापदंडों के रूप में पास किया जा रहा है, कार्यों से लौटाया गया है, और चर में संग्रहीत किया गया है, लैम्ब्डा का प्रतिनिधित्व करने के लिए, और उन्हें अपने संलग्न वातावरण के साथ-साथ मशीन कोड को उस संदर्भ में चलाने के लिए अनुमति देता है। लेकिन यह सिर्फ एक रास्ता (कई में से एक) के लिए लागू बंद, नहीं बंद ही।
जैसा कि मैंने ऊपर बताया, लैम्ब्डा एक्सप्रेशन को बंद करना इसके वातावरण में परिभाषाओं का सबसेट है जो लैम्बडा एक्सप्रेशन में निहित फ्री वैरिएबल्स को वैल्यू देते हैं, एक्सप्रेशन को प्रभावी रूप से बंद करते हैं (एक ओपन लैम्ब्डा एक्सप्रेशन को बदलते हुए, जिसका मूल्यांकन अभी तक नहीं किया जा सकता है, एक बंद लैम्ब्डा अभिव्यक्ति, जिसे तब मूल्यांकन किया जा सकता है, क्योंकि इसमें निहित सभी प्रतीकों को अब परिभाषित किया गया है)।
और कुछ भी नहीं बस एक "कार्गो पंथ" और प्रोग्रामर्स और भाषा विक्रेताओं के "वू-डू जादू" है जो इन धारणाओं की वास्तविक जड़ों से अनजान हैं।
मैं आशा करता हूँ कि यह आपके प्रश्नों का उत्तर देगा। लेकिन अगर आपके पास कोई अनुवर्ती प्रश्न थे, तो उन्हें टिप्पणियों में पूछने के लिए स्वतंत्र महसूस करें, और मैं इसे बेहतर तरीके से समझाने की कोशिश करूंगा।
जब अधिकांश लोग कार्यों के बारे में सोचते हैं , तो वे नामित कार्यों के बारे में सोचते हैं :
function foo() { return "This string is returned from the 'foo' function"; }
इन्हें नाम से पुकारा जाता है, बेशक:
foo(); //returns the string above
लंबोदर भाव के साथ , आपके अनाम कार्य हो सकते हैं :
@foo = lambda() {return "This is returned from a function without a name";}
उपरोक्त उदाहरण के साथ, आप लैम्बडा को उस चर के माध्यम से कॉल कर सकते हैं जिसे इसे सौंपा गया था:
foo();
अनाम फ़ंक्शंस को वेरिएबल्स में असाइन करने से अधिक उपयोगी, हालांकि, उन्हें उच्च-ऑर्डर फ़ंक्शंस से, या उन फ़ंक्शंस से, जो उन फ़ंक्शंस को स्वीकार / वापस करने के लिए पास कर रहे हैं। इनमें से कई मामलों में, एक फ़ंक्शन का नामकरण आवश्यक है:
function filter(list, predicate)
{ @filteredList = [];
for-each (@x in list) if (predicate(x)) filteredList.add(x);
return filteredList;
}
//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)});
एक बंद एक नामित किया जा सकता है या अनाम समारोह है, लेकिन इस तरह के रूप में जाना जाता है जब दायरे में चर जहां समारोह, परिभाषित किया गया है यानी, बंद अभी तक किसी भी बाहरी चर में किया जाता है के साथ पर्यावरण के लिए संदर्भित करेंगे यह "पर बंद" खुद को बंद करो। यहाँ एक नाम बंद है:
@x = 0;
function incrementX() { x = x + 1;}
incrementX(); // x now equals 1
यह बहुत ज्यादा नहीं लगता है, लेकिन क्या होगा अगर यह किसी अन्य फ़ंक्शन में था और आप incrementX
किसी बाहरी फ़ंक्शन में गए थे?
function foo()
{ @x = 0;
function incrementX()
{ x = x + 1;
return x;
}
return incrementX;
}
@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)
यह है कि आप कार्यात्मक प्रोग्रामिंग में स्टेटफुल ऑब्जेक्ट कैसे प्राप्त करते हैं। चूंकि "incrementX" का नामकरण आवश्यक नहीं है, इसलिए आप इस मामले में एक लैम्ब्डा का उपयोग कर सकते हैं:
function foo()
{ @x = 0;
return lambda()
{ x = x + 1;
return x;
};
}
सभी क्लोजर लैम्ब्डा नहीं हैं और सभी लैम्बडा क्लोजर नहीं हैं। दोनों फ़ंक्शन हैं, लेकिन जरूरी नहीं कि जिस तरीके से हम जानने के लिए उपयोग किए जाते हैं।
एक लैम्ब्डा अनिवार्य रूप से एक फ़ंक्शन है जिसे फ़ंक्शन घोषित करने की मानक विधि के बजाय इनलाइन परिभाषित किया गया है। लंबोदर अक्सर वस्तुओं के रूप में चारों ओर पारित किया जा सकता है।
एक समापन एक ऐसा कार्य है जो अपने शरीर के बाहरी क्षेत्रों को संदर्भित करके अपने आसपास के राज्य को घेरता है। संलग्न राज्य बंद के आह्वान पर रहता है।
ऑब्जेक्ट-ओरिएंटेड भाषा में, क्लोज़र सामान्य रूप से ऑब्जेक्ट्स के माध्यम से प्रदान किए जाते हैं। हालाँकि, कुछ OO भाषाएँ (जैसे C #) विशेष कार्यक्षमता को लागू करती हैं जो विशुद्ध रूप से कार्यात्मक भाषाओं (जैसे लिस्प) द्वारा प्रदान की जाने वाली क्लोज़र की परिभाषा के करीब होती हैं, जिसमें राज्य को घेरने के लिए ऑब्जेक्ट नहीं होते हैं।
मजे की बात यह है कि C # में लैंबडास और क्लोजर की शुरूआत कार्यात्मक प्रोग्रामिंग को मुख्यधारा के उपयोग के करीब लाती है।
यह उतना ही सरल है: लैम्ब्डा एक भाषा निर्माण है, यानी गुमनाम कार्यों के लिए केवल वाक्य रचना; क्लोजर इसे लागू करने की एक तकनीक है - या किसी भी प्रथम श्रेणी के कार्यों के लिए, इस मामले के लिए, नाम या अनाम।
अधिक सटीक रूप से, एक क्लोजर यह है कि रन-टाइम पर एक फर्स्ट-क्लास फ़ंक्शन का प्रतिनिधित्व कैसे किया जाता है, इसके कोड में उपयोग किए गए सभी गैर-स्थानीय चर पर एक "कोड" और एक पर्यावरण "क्लोजिंग" के रूप में। इस तरह, वे चर अभी भी सुलभ हैं, जब बाहरी स्कोप जहां वे उत्पन्न होते हैं, वे पहले से ही बाहर निकल चुके हैं।
दुर्भाग्य से, वहाँ कई भाषाएँ हैं जो फ़र्स्ट-क्लास मानों के रूप में फ़ंक्शंस का समर्थन नहीं करती हैं, या केवल अपंग रूप में उनका समर्थन करती हैं। इसलिए लोग अक्सर "असली चीज़" को अलग करने के लिए "बंद" शब्द का उपयोग करते हैं।
प्रोग्रामिंग भाषाओं के दृष्टिकोण से, वे पूरी तरह से दो अलग-अलग चीजें हैं।
मूल रूप से ट्यूरिंग पूरी भाषा के लिए हमें केवल बहुत सीमित तत्वों की आवश्यकता होती है, जैसे अमूर्तता, अनुप्रयोग और कमी। अमूर्तता और अनुप्रयोग जिस तरह से आप लैम्ब्डा अभिव्यक्ति का निर्माण कर सकते हैं, और कमी लैम्ब्डा अभिव्यक्ति के अर्थ को नष्ट कर देती है।
लैम्ब्डा एक तरीका प्रदान करता है जिससे आप गणना प्रक्रिया को समाप्त कर सकते हैं। उदाहरण के लिए, दो संख्याओं के योग की गणना करने के लिए, एक प्रक्रिया जो दो मापदंडों को लेती है x, y और रिटर्न x + y को अलग किया जा सकता है। योजना में, आप इसे लिख सकते हैं
(lambda (x y) (+ x y))
आप मापदंडों का नाम बदल सकते हैं, लेकिन इसे पूरा करने वाला कार्य नहीं बदलता है। लगभग सभी प्रोग्रामिंग भाषाओं में, आप लैम्ब्डा एक्सप्रेशन को एक नाम दे सकते हैं, जिसे फंक्शन नाम दिया गया है। लेकिन बहुत अधिक अंतर नहीं है, उन्हें वैचारिक रूप से सिर्फ वाक्यविन्यास चीनी के रूप में माना जा सकता है।
ठीक है, अब कल्पना करें कि इसे कैसे लागू किया जा सकता है। जब भी हम कुछ भावों के लिए लंबोदर अभिव्यक्ति को लागू करते हैं, उदा
((lambda (x y) (+ x y)) 2 3)
हम बस मूल्यांकन किए जाने वाले अभिव्यक्ति के साथ मापदंडों को प्रतिस्थापित कर सकते हैं। यह मॉडल पहले से ही बहुत शक्तिशाली है। लेकिन यह मॉडल हमें प्रतीकों के मूल्यों को बदलने में सक्षम नहीं करता है, जैसे हम स्थिति के परिवर्तन की नकल नहीं कर सकते। इस प्रकार हमें एक अधिक जटिल मॉडल की आवश्यकता है। इसे कम करने के लिए, जब भी हम लंबोदर अभिव्यक्ति के अर्थ की गणना करना चाहते हैं, तो हम प्रतीक की जोड़ी और एक पर्यावरण (या तालिका) में संबंधित मूल्य डालते हैं। तब बाकी (+ xy) का मूल्यांकन तालिका में संबंधित प्रतीकों को देखकर किया जाता है। अब अगर हम सीधे पर्यावरण पर काम करने के लिए कुछ आदिम प्रदान करते हैं, तो हम स्थिति के परिवर्तनों को मॉडल कर सकते हैं!
इस पृष्ठभूमि के साथ, इस फ़ंक्शन की जाँच करें:
(lambda (x y) (+ x y z))
हम जानते हैं कि जब हम लंबोदर अभिव्यक्ति का मूल्यांकन करते हैं, तो xy एक नई तालिका में बंध जाएगा। लेकिन हम z कैसे और कहाँ देख सकते हैं? दरअसल z को एक फ्री वैरिएबल कहा जाता है। एक बाहरी वातावरण होना चाहिए जिसमें z शामिल हो। अन्यथा अभिव्यक्ति का अर्थ केवल बाध्यकारी x और y द्वारा निर्धारित नहीं किया जा सकता है। इसे स्पष्ट करने के लिए, आप योजना में निम्नानुसार कुछ लिख सकते हैं:
((lambda (z) (lambda (x y) (+ x y z))) 1)
तो z बाहरी तालिका में 1 से बंधा होगा। हमें अभी भी एक फ़ंक्शन मिलता है जो दो मापदंडों को स्वीकार करता है लेकिन इसका वास्तविक अर्थ बाहरी वातावरण पर भी निर्भर करता है। दूसरे शब्दों में, बाहरी वातावरण मुक्त चर पर बंद हो जाता है। सेट की मदद से!, हम फंक्शन को स्टेटफुल बना सकते हैं, यानी यह मैथ्स के लिहाज से कोई फंक्शन नहीं है। यह जो रिटर्न देता है वह न केवल इनपुट पर निर्भर करता है, बल्कि z भी है।
यह एक ऐसी चीज है जिसे आप पहले से ही अच्छी तरह से जानते हैं, वस्तुओं की एक विधि लगभग हमेशा वस्तुओं की स्थिति पर निर्भर करती है। इसीलिए कुछ लोग कहते हैं "बंद गरीब आदमी की वस्तुएं हैं।" लेकिन हम वस्तुओं को गरीब आदमी की बंदियों के रूप में भी मान सकते हैं क्योंकि हम वास्तव में प्रथम श्रेणी के कार्यों को पसंद करते हैं।
मैं योजना का उपयोग विचारों को समझने के लिए करता हूं क्योंकि यह योजना सबसे शुरुआती भाषा में से एक है, जिसमें वास्तविक क्लोजर हैं। यहां सभी सामग्री SICP अध्याय 3 में बेहतर ढंग से प्रस्तुत की गई हैं।
योग करने के लिए, लैम्ब्डा और क्लोजर वास्तव में अलग-अलग अवधारणाएं हैं। एक लंबोदर एक फ़ंक्शन है। क्लोजर लैम्ब्डा की एक जोड़ी है और संबंधित वातावरण जो लैम्ब्डा को बंद करता है।
कॉन्सेप्ट ऊपर वर्णित के समान है, लेकिन यदि आप PHP पृष्ठभूमि से हैं, तो यह आगे PHP कोड का उपयोग करके समझाता है।
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });
फ़ंक्शन ($ v) {$ $ v> 2; } लैम्बडा फंक्शन की परिभाषा है। हम इसे एक चर में भी संग्रहीत कर सकते हैं, इसलिए इसे पुन: प्रयोज्य किया जा सकता है:
$max = function ($v) { return $v > 2; };
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);
अब, क्या होगा यदि आप फ़िल्टर किए गए सरणी में अनुमत अधिकतम संख्या को बदलना चाहते हैं? आपको एक और लंबो फंक्शन लिखना होगा या एक क्लोजर (PHP 5.3) बनाना होगा:
$max_comp = function ($max) {
return function ($v) use ($max) { return $v > $max; };
};
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));
एक क्लोजर एक फ़ंक्शन है जिसका मूल्यांकन अपने स्वयं के वातावरण में किया जाता है, जिसमें एक या एक से अधिक बाध्य चर होते हैं जिन्हें फ़ंक्शन कहा जाता है। वे कार्यात्मक प्रोग्रामिंग की दुनिया से आते हैं, जहां खेलने में कई अवधारणाएं हैं। क्लोजर लैंबडा फंक्शन्स की तरह होते हैं, लेकिन इस मायने में होशियार होते हैं कि वे बाहरी वातावरण से वैरिएबल के साथ इंटरैक्ट करने की क्षमता रखते हैं, जहां क्लोजर को परिभाषित किया जाता है।
यहाँ PHP बंद करने का एक सरल उदाहरण है:
$string = "Hello World!";
$closure = function() use ($string) { echo $string; };
$closure();
यह सवाल पुराना है और कई उत्तर मिला है।
अब जावा 8 और आधिकारिक लैम्ब्डा के साथ जो अनौपचारिक बंद परियोजनाएं हैं, यह प्रश्न को पुनर्जीवित करता है।
जावा संदर्भ में जवाब ( लम्बदा और बंद के माध्यम से - क्या अंतर है? ):
"एक बंद एक लैम्बडा अभिव्यक्ति है जो एक पर्यावरण के साथ जोड़ा जाता है जो इसके प्रत्येक फ्री वैरिएबल को एक वैल्यू के साथ बांधता है। जावा में, लैम्ब्डा एक्सप्रेशन को क्लोजर के माध्यम से लागू किया जाएगा, इसलिए समुदाय में दो शब्दों का परस्पर उपयोग किया गया है।"
सीधे शब्दों में कहें तो क्लोजर स्कोप के बारे में एक ट्रिक है, लैम्बडा एक गुमनाम फंक्शन है। हम महसूस कर सकते हैं कि लैम्बडा के साथ और अधिक भव्यता के साथ क्लोजर किया जाता है और लैम्बडा को अक्सर एक उच्च फ़ंक्शन के लिए दिए गए पैरामीटर के रूप में उपयोग किया जाता है
एक लैंबडा अभिव्यक्ति केवल एक अनाम फ़ंक्शन है। सादे जावा में, उदाहरण के लिए, आप इसे इस तरह लिख सकते हैं:
Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
public Job apply(Person person) {
Job job = new Job(person.getPersonId(), person.getJobDescription());
return job;
}
};
जहाँ क्लास फंक्शन सिर्फ जावा कोड में बनाया गया है। अब आप mapPersonToJob.apply(person)
इसे उपयोग करने के लिए कहीं कॉल कर सकते हैं । सिर्फ एक उदाहरण है। इससे पहले कि वहाँ एक वाक्यविन्यास था के लिए वाक्यविन्यास Thats। इसके लिए लैम्ब्डा ने एक शॉर्ट कट किया।
बंद:
एक लैम्ब्डा एक बंद हो जाता है जब यह इस दायरे से बाहर चर का उपयोग कर सकता है। मुझे लगता है कि आप इसका जादू कह सकते हैं, यह जादुई रूप से उस वातावरण के चारों ओर लपेट सकता है जो इसे बनाया गया था और इसके बाहरी भाग (बाहरी क्षेत्र) के बाहर चर का उपयोग करता है। इसलिए स्पष्ट होने के लिए, एक बंद का मतलब है कि एक लैम्बडा अपने OUTER SCOPE तक पहुंच सकता है।
कोटलिन में, एक लैम्ब्डा हमेशा अपने क्लोजर तक पहुंच सकता है (चर जो इसके बाहरी दायरे में हैं)
यह इस बात पर निर्भर करता है कि कोई फ़ंक्शन बाहरी चर का उपयोग करता है या ऑपरेशन करने के लिए नहीं।
बाहरी चर - किसी फ़ंक्शन के दायरे के बाहर परिभाषित चर।
लैम्ब्डा के भाव स्टेटलेस हैं क्योंकि यह ऑपरेशन करने के लिए मापदंडों, आंतरिक चर या स्थिरांक पर निर्भर करता है।
Function<Integer,Integer> lambda = t -> {
int n = 2
return t * n
}
क्लोजर राज्य को धारण करते हैं क्योंकि यह ऑपरेशन करने के लिए मापदंडों और स्थिरांक के साथ-साथ बाहरी चर (यानी फ़ंक्शन बॉडी के दायरे के बाहर परिभाषित चर) का उपयोग करता है।
int n = 2
Function<Integer,Integer> closure = t -> {
return t * n
}
जब Java क्लोजर बनाता है, तो यह वेरिएबल n को फंक्शन के साथ रखता है, ताकि इसे अन्य फंक्शन्स में पास किया जा सके या कहीं भी इस्तेमाल किया जा सके।