2012-07-30 10 views
24

मैं गतिशील चर और बाध्यकारी समारोह समझने की कोशिश की तो मैं यह करने की कोशिश की (clojure 1.3):clojure और ^: गतिशील

user=> (defn f [] 
      (def ^:dynamic x 5) 
      (defn g [] (println x)) 
      (defn h [] (binding [x 3] (g))) 
      (h)) 
#'user/f 
user=> (f)  
5 
nil 

उलझन में, मैं यह कुछ हद तक सरल कोड की कोशिश की:

user=> (def ^:dynamic y 5) 
#'user/y 
user=> (defn g [] (println y)) 
#'user/g 
user=> (defn h [] (binding [y 3] (g))) 
#'user/h 
user=> (h) 
3 
nil 

क्या कोड के दो टुकड़ों के बीच अंतर है? दूसरा उदाहरण क्यों काम करता है लेकिन पहला नहीं है?

सुझाव: मैं सिर्फ महसूस किया कि निम्न काम करता है (अब भी है पूरी तरह से क्यों समझ में नहीं आता):

user=> (def ^:dynamic y 5) 
#'user/y 
user=> (defn f [] (defn g [] (println y)) (defn h [] (binding [y 3] (g))) (h)) 
#'user/f 
user=> (f) 
3 
nil 
user=> 

उत्तर

26

मैं एक परिणाम के रूप में 3 मिल (जैसा कि आप उम्मीद करेंगे) जब मैं Clojure में अपना पहला उदाहरण चलाने 1.4 .... क्या आपने इसे एक नए आरईपीएल के साथ करने की कोशिश की है?

^:dynamic Clojure संकलक है कि एक प्रतीक (के रूप में def साथ परिभाषित) गतिशील (binding के साथ) पलटाव करने का इरादा है करने के लिए एक निर्देश है।

उदाहरण:

(def foo 1) 
(binding [foo 2] foo) 
=> IllegalStateException Can't dynamically bind non-dynamic var: ... 

(def ^:dynamic bar 10) 
(binding [bar 20] bar) ;; dynamically bind bar within the scope of the binding 
=> 20 
bar      ;; check underlying value of bar (outside the binding) 
=> 10 

ध्यान दें कि binding बुला धागे के भीतर गतिशील गुंजाइश है - किसी भी कार्य करता है बंधन के भीतर बुलाया bar (20) के संशोधित मूल्य देखेंगे, लेकिन किसी अन्य सूत्र अभी भी कोई बदलाव नहीं देखेंगे 10

अंत में है कि आप उपयोगी मिल सकता है शैली अंक की एक जोड़ी की जड़ मूल्य:

  • यह आम तौर पर सी है def और defn को कार्यक्षेत्रों के रूप में रखने के लिए खराब विचार पर विचार किया गया है क्योंकि वे संलग्न नामस्थान को प्रभावित करते हैं। कार्यों के भीतर आपको इसके बजाय (let [foo bar] ...) का उपयोग करना चाहिए।
  • जब आप खुद को binding का उपयोग करना चाहते हैं तो आपको आम तौर पर यह विचार करना चाहिए कि आप इसके बजाय उच्च आदेश फ़ंक्शंस का उपयोग करके एक ही परिणाम प्राप्त कर सकते हैं या नहीं। binding कुछ संदर्भों में उपयोगी है लेकिन सामान्य रूप से यह पैरामीटर को पारित करने का एक अच्छा तरीका नहीं है - फ़ंक्शन संरचना आमतौर पर लंबे समय तक बेहतर होती है। इसका कारण यह है कि binding एक अंतर्निहित संदर्भ बनाता है जो आपके फ़ंक्शन के निष्पादन के लिए आवश्यक है और परीक्षण/डीबग करना मुश्किल हो सकता है।
+0

मैं बाइंडिंग के पेशेवर/विपक्ष को समझता हूं। मुझे यह भी पता है कि पहला कोड उदाहरण असामान्य क्लोजर कोड है। मुझे समझ में नहीं आया कि यह क्यों काम नहीं करता (1.3, ताजा प्रतिलिपि के साथ)। – Kevin

+0

मुझे परेशानी हो रही है जब आप कभी बाध्यकारी चाहते हैं! यह कार्यात्मक तरीके से अनाथाश्रम दिखता है। मैं क्या खो रहा हूँ ? – Hendekagon

+1

@ हेंडेकैगन - शायद अपने स्वयं के अधिकार में एक SO प्रश्न का हकदार है। लेकिन मुझे आरईपीएल में डिबगिंग/काम करते समय गोल संदर्भ पारित करने के एक अतिरिक्त तरीके के रूप में उपयोगी पाया गया है - यदि आपने इसे पूरी तरह से कार्यात्मक तरीके से किया है तो आपको एक (संभावित रूप से बहुत लंबी) कॉल के माध्यम से सभी तरह से नए पैरामीटर थ्रेड करना होगा ग्राफ। – mikera