बहुत जल्दी: एक प्रतिस्थापन "संदर्भित रूप से पारदर्शी" है अगर "प्रतिस्थापन की तरह होता है" और एक फ़ंक्शन "शुद्ध" है यदि इसके प्रभाव के सभी इसके वापसी मूल्य में निहित हैं। उन दोनों को सटीक बनाया जा सकता है, लेकिन यह ध्यान रखना महत्वपूर्ण है कि वे समान नहीं हैं और न ही एक दूसरे को भी नापसंद करते हैं।
अब बात करते हैं क्लोजर की।
बोरिंग (ज्यादातर शुद्ध) "बंद"
क्लोज़र इसलिए होता है क्योंकि जब हम लैम्बडा शब्द का मूल्यांकन करते हैं तो हम पर्यावरण के लुकअप के रूप में चर (बाउंड) की व्याख्या करते हैं। इस प्रकार, जब हम एक लंबोदर शब्द का मूल्यांकन करते हैं, तो मूल्यांकन के परिणामस्वरूप इसके अंदर के चर उन मूल्यों को "बंद" कर देते हैं, जिन्हें उन्होंने परिभाषित किया था।
सादे लैम्ब्डा कैलकुलस में यह तुच्छ की तरह है और पूरी धारणा बस गायब हो जाती है। यह प्रदर्शित करने के लिए, यहाँ एक अपेक्षाकृत हल्का लैम्ब्डा कैलकुलस दुभाषिया है:
-- untyped lambda calculus values are functions
data Value = FunVal (Value -> Value)
-- we write expressions where variables take string-based names, but we'll
-- also just assume that nobody ever shadows names to avoid having to do
-- capture-avoiding substitutions
type Name = String
data Expr
= Var Name
| App Expr Expr
| Abs Name Expr
-- We model the environment as function from strings to values,
-- notably ignoring any kind of smooth lookup failures
type Env = Name -> Value
-- The empty environment
env0 :: Env
env0 _ = error "Nope!"
-- Augmenting the environment with a value, "closing over" it!
addEnv :: Name -> Value -> Env -> Env
addEnv nm v e nm' | nm' == nm = v
| otherwise = e nm
-- And finally the interpreter itself
interp :: Env -> Expr -> Value
interp e (Var name) = e name -- variable lookup in the env
interp e (App ef ex) =
let FunVal f = interp e ef
x = interp e ex
in f x -- application to lambda terms
interp e (Abs name expr) =
-- augmentation of a local (lexical) environment
FunVal (\value -> interp (addEnv name value e) expr)
नोटिस करने के लिए महत्वपूर्ण हिस्सा है addEnv
जब हम एक नए नाम के साथ पर्यावरण को बढ़ाते हैं। इस फ़ंक्शन को केवल व्याख्या किए गए Abs
कर्षण शब्द (लैम्ब्डा शब्द) के "अंदर" कहा जाता है । पर्यावरण "देखा" हो जाता है जब भी हम एक मूल्यांकन Var
अवधि और उन Var
को रों संकल्प जो कुछ Name
में निर्दिष्ट Env
है जिसके द्वारा कब्जा कर लिया गया Abs
युक्त कर्षण Var
।
अब, फिर से, सादे LC शब्दों में यह उबाऊ है। इसका मतलब यह है कि बाध्य चर सिर्फ स्थिरांक हैं जहाँ तक किसी को परवाह है। वे सीधे और तुरंत मूल्यांकन करते हैं क्योंकि वे पर्यावरण में निरूपित मानों के रूप में लेक्सिकली उस बिंदु तक पहुंच जाते हैं।
यह भी (लगभग) शुद्ध है। हमारे लैम्ब्डा कैलकुलस में किसी भी शब्द का एकमात्र अर्थ इसके वापसी मूल्य से निर्धारित होता है। एकमात्र अपवाद गैर-समाप्ति का साइड-इफेक्ट है जो ओमेगा शब्द द्वारा सन्निहित है:
-- in simple LC syntax:
--
-- (\x -> (x x)) (\x -> (x x))
omega :: Expr
omega = App (Abs "x" (App (Var "x")
(Var "x")))
(Abs "x" (App (Var "x")
(Var "x")))
दिलचस्प (अशुद्ध) बंद
अब कुछ पृष्ठभूमि के लिए ऊपर दिए गए सादे नियंत्रण रेखा में वर्णित उबाऊ उबाऊ हैं क्योंकि हमारे द्वारा बंद किए गए चर के साथ बातचीत करने में सक्षम होने की कोई धारणा नहीं है। विशेष रूप से, शब्द "क्लोजर" निम्नलिखित जावास्क्रिप्ट जैसे कोड को आमंत्रित करता है
> function mk_counter() {
var n = 0;
return function incr() {
return n += 1;
}
}
undefined
> var c = mk_counter()
undefined
> c()
1
> c()
2
> c()
3
यह दर्शाता है कि हमने n
आंतरिक फ़ंक्शन में चर पर बंद कर दिया है incr
और incr
उस चर के साथ सार्थक रूप से बातचीत कर रहा है। mk_counter
शुद्ध है, लेकिन incr
निश्चित रूप से अशुद्ध है (और संदर्भित पारदर्शी भी नहीं)।
इन दो उदाहरणों के बीच क्या अंतर है?
"परिवर्तनशील" की धारणाएँ
अगर हम देखते हैं कि सादे LC अर्थ में प्रतिस्थापन और अमूर्तता का क्या अर्थ है, तो हम देखते हैं कि वे निश्चित रूप से सादे हैं। चर वास्तव में तत्काल पर्यावरण लुकअप से ज्यादा कुछ नहीं हैं । लैम्ब्डा अमूर्तता का शाब्दिक रूप से आंतरिक अभिव्यक्ति का मूल्यांकन करने के लिए एक संवर्धित वातावरण बनाने से ज्यादा कुछ नहीं है । इस तरह के व्यवहार के लिए इस मॉडल में कोई जगह नहीं है जिसे हमने देखा mk_counter
/ incr
क्योंकि वहाँ कोई भिन्नता की अनुमति नहीं है।
बहुतों के लिए यह "चर" का अर्थ है- भिन्नता। हालांकि, अर्थशास्त्री एलसी में इस्तेमाल किए गए चर के प्रकार और जावास्क्रिप्ट में उपयोग किए जाने वाले "चर" के बीच अंतर करना पसंद करते हैं। ऐसा करने के लिए, वे बाद वाले को "म्यूटेबल सेल" या "स्लॉट" कहते हैं।
यह नामकरण गणित में "चर" के लंबे ऐतिहासिक उपयोग का अनुसरण करता है, जहां इसका अर्थ "अज्ञात" की तरह कुछ और होता है: (गणितीय) अभिव्यक्ति "x + x" x
समय के साथ अलग-अलग होने की अनुमति नहीं देता है , इसके बजाय इसका अर्थ है (एकल, स्थिर) मान x
लेता है।
इस प्रकार, हम "स्लॉट" कहते हैं कि एक स्लॉट में मूल्यों को डालने और उन्हें बाहर निकालने की क्षमता पर जोर दिया जाए।
भ्रम को और जोड़ने के लिए, जावास्क्रिप्ट में ये "स्लॉट्स" वैरिएबल के समान दिखते हैं: हम लिखते हैं
var x;
एक बनाने के लिए और फिर जब हम लिखते हैं
x;
यह इंगित करता है कि वर्तमान में उस स्लॉट में संग्रहीत मान को देख रहे हैं। इसे और अधिक स्पष्ट करने के लिए, शुद्ध भाषाएं स्लॉट्स के नाम के रूप में (गणितीय, लैम्ब्डा कैलकुलस) नाम लेने की सोचती हैं। इस मामले में हमें एक स्लॉट से स्पष्ट रूप से लेबल करना चाहिए। इस तरह की संकेतन जैसी दिखती है
-- create a fresh, empty slot and name it `x` in the context of the
-- expression E
let x = newSlot in E
-- look up the value stored in the named slot named `x`, return that value
get x
-- store a new value, `v`, in the slot named `x`, return the slot
put x v
इस अंकन का लाभ यह है कि अब हमारे पास गणितीय चर और उत्परिवर्ती स्लॉट के बीच एक मजबूत अंतर है। चर अपने मूल्यों के रूप में स्लॉट ले सकते हैं, लेकिन एक चर द्वारा नामित विशेष स्लॉट इसके दायरे में निरंतर है।
इस अंकन का उपयोग करके हम mk_counter
उदाहरण को फिर से लिख सकते हैं (इस बार हास्केल-जैसे सिंटैक्स में, हालांकि निश्चित रूप से संयुक्त राष्ट्र-हास्केल जैसे शब्दार्थ):
mkCounter =
let x = newSlot
in (\() -> let old = get x
in get (put x (old + 1)))
इस मामले में हम ऐसी प्रक्रियाओं का उपयोग कर रहे हैं जो इस परिवर्तनशील स्लॉट में हेरफेर करती हैं। इसे कार्यान्वित करने के लिए हमें न केवल नामों की एक निरंतर वातावरण की आवश्यकता होती है, x
बल्कि सभी आवश्यक स्लॉट्स के साथ एक परस्पर वातावरण भी होता है। यह "बंद" लोगों की आम धारणा के करीब है जो लोग बहुत प्यार करते हैं।
फिर, mkCounter
बहुत अशुद्ध है। यह भी बहुत संदर्भ से अपारदर्शी है। लेकिन ध्यान दें कि साइड-इफेक्ट नाम पकड़ने या बंद करने से उत्पन्न नहीं होते हैं, बल्कि उत्परिवर्तित सेल के कैप्चर और उस पर साइड-इफ़ेक्टिंग ऑपरेशंस जैसे get
और put
।
अंततः, मुझे लगता है कि यह आपके प्रश्न का अंतिम उत्तर है: शुद्धता (गणितीय) चर कैप्चर से प्रभावित नहीं होती है, बल्कि इसके बजाय पकड़े गए चर द्वारा नामित उत्परिवर्तित स्लॉट पर किए गए साइड-इफ़ेक्टिंग ऑपरेशंस द्वारा प्रभावित होती है।
यह केवल उन भाषाओं में है जो एलसी के करीब होने का प्रयास नहीं करते हैं या शुद्धता बनाए रखने का प्रयास नहीं करते हैं कि इन दो अवधारणाओं को अक्सर भ्रम की स्थिति में लाया जाता है।