2012-02-06 10 views
37

मैं समझने की कोशिश कर रहा हूं कि ^:const क्लोजर में क्या करता है। देव डॉक्स कहते हैं। http://dev.clojure.org/display/doc/1.3क्लोजर^कैसे काम करता है?

(डीईएफ़ स्थिरांक {: अनुकरणीय 3.14 : ई 2.71})

(डीईएफ़ ^: स्थिरांक अनुकरणीय (: अनुकरणीय स्थिरांक)) (डीईएफ़ ^: स्थिरांक ई (: ई स्थिरांक))

देखरेख करने का ऊपरी भाग: ई और: मानचित्र में पीआई संकलन समय पर होता है, क्योंकि (: पीआई स्थिरांक) और (: ई स्थिरांक) का मूल्यांकन किया जाता है जब उनके माता-पिता के रूपों का मूल्यांकन किया जाता है।

क्योंकि मेटाडेटा वर प्रतीक pi करने के लिए बाध्य करने के लिए है, और वर प्रतीक e करने के लिए बाध्य है, फिर भी नीचे वाक्य यह नक्शा लुकअप, नहीं वर लुकअप में तेजी लाने में मदद करता है का कहना है कि यह भ्रामक है।

क्या कोई यह बता सकता है कि ^:const क्या कर रहा है और इसका उपयोग करने के पीछे तर्क? यह एक विशाल let ब्लॉक का उपयोग करने या (pi) और (e) जैसे मैक्रो का उपयोग करने की तुलना कैसे करता है?

उत्तर

56

यह मेरे लिए एक बुरा उदाहरण जैसा दिखता है, क्योंकि मानचित्र-लुकअप के बारे में सामान सिर्फ इस मुद्दे को भ्रमित करता है।

एक और अधिक यथार्थवादी उदाहरण होगा:

(def pi 3.14) 
(defn circumference [r] (* 2 pi r)) 

इस मामले में, परिधि के शरीर कोड जो रनटाइम के दौरान पाई dereferences (Var.getRawRoot फोन करके) में संकलित किया गया है, हर बार जब परिधि कहा जाता है।

(defn circumference [r] (* 2 3.14 r)) 

है, Var.getRawRoot करने के लिए कॉल, को छोड़ दिया है जो एक सहेजता है:

(def ^:const pi 3.14) 
(defn circumference [r] (* 2 pi r)) 

इस मामले में, परिधि के रूप में अगर यह इस तरह लिखा गया था ठीक उसी कोड में संकलित किया गया है थोड़ा सा समय यहां एक त्वरित माप, जहां circ ऊपर पहला संस्करण है, और circ2 पीछे नहीं है:

user> (time (dotimes [_ 1e5] (circ 1))) 
"Elapsed time: 16.864154 msecs" 
user> (time (dotimes [_ 1e5] (circ2 1))) 
"Elapsed time: 6.854782 msecs" 
+0

क्या इसका मतलब यह है कि निम्नलिखित (def ^: const key-to-num {: one 1: two 2}) (डीफ़ योग (+ (: एक कुंजी-टू-num) (: दो कुंजी-टू- संख्या)) को संकलित किया गया है (डीईएफ़ योग (+ 1 2)) –

+0

नहीं, ^: स्थिरांक केवल आदिम मूल्यों, नहीं मनमाने ढंग से वस्तुओं – noisesmith

9

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

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

यह एक समेकित उदाहरण है क्योंकि कक्षा लोड समय पर एक नक्शा लुकअप और रनटाइम पर कुछ var लुकअप मूल रूप से कुछ भी नहीं हैं, हालांकि यह इस बिंदु को दर्शाता है कि कुछ काम संकलन समय पर कुछ होता है, कुछ लोड समय पर, और बाकी अच्छी तरह से। .. शेष समय

+2

मुझे नहीं लगता कि यह सही है। अधिक महत्वपूर्ण बचत नक्शा-लुकअप नहीं है, लेकिन 'pi' और' e' के लिए var-lookup, जो हर बार जब आप '^: const' की कमी करते हैं तो उनमें से किसी एक को संदर्भित किया जाएगा, लेकिन यह नहीं होता है सब जब '^: const' शामिल है। – amalloy

+0

यह इंगित करने के लिए धन्यवाद, मैंने var lookup को भी जोड़ने के लिए संपादित किया है। –

8

दक्षता पहलू ऊपर वर्णित के अलावा, वहाँ एक सुरक्षा के पहलू भी उपयोगी है।निम्नलिखित कोड पर विचार करें:

(def two 2) 
(defn times2 [x] (* two x)) 
(assert (= 4 (times2 2))) ; Expected result 

(def two 3)     ; Ooops! The value of the "constant" changed 
(assert (= 6 (times2 2))) ; Used the new (incorrect) value 

(def ^:const const-two 2) 
(defn times2 [x] (* const-two x)) 
(assert (= 4 (times2 2))) ; Still works 

(def const-two 3)   ; No effect! 
(assert (= 3 const-two)) ; It did change... 
(assert (= 4 (times2 2))) ; ...but the function did not. 

तो,^का उपयोग करके: जब वार्स को परिभाषित स्थिरांक मेटाडाटा, वार्स प्रभावी रूप से कर रहे हैं हर जगह वे उपयोग किया जाता है में "inlined"। Var में कोई भी परिवर्तन, इसलिए, किसी भी कोड को प्रभावित नहीं करता है जहां "पुराना" मान पहले से ही रेखांकित किया गया है।

^: const का उपयोग भी एक प्रलेखन कार्य करता है। जब कोई पढ़ता है (def ^: const pi 3.14159) पाठक को बताता है कि var pi को कभी भी बदलने का इरादा नहीं है, यह मूल्य 3.1415 9 के लिए बस एक सुविधाजनक (& उम्मीदवार वर्णनात्मक) नाम है।

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

^:const var को बदलने का प्रयास करने पर अपवाद को फेंकने का एक बेहतर समाधान होगा।

+1

[Clojure स्टाइल गाइड] (https पर काम करता है: // GitHub। com/bbatsov/clojure-style-guide # नामकरण) कहते हैं, "स्थिरांक के लिए एक विशेष नोटेशन का उपयोग न करें; अन्यथा निर्दिष्ट किए जाने तक सब कुछ स्थिर माना जाता है।" क्या यह सुझाव देता है कि मूल्य नियमित रूप से रेखांकित होते हैं, कम से कम जब वे फिर से नहीं होते हैं -'def'ed? (हो सकता है कि^^: const' का अर्थ केवल "इन चर के बाद के 'def' होने पर भी इनलाइन हो सकता है", लेकिन यदि बाद में' def' नहीं है, यहां तक ​​कि गैर-^^ const'ed vars mig एचटी इनलाइन हो जाओ? मेरा बहुत जंगली अनुमान।) या यदि '^: const'ed vars अलग हैं, तो मुझे नामकरण द्वारा स्पष्ट क्यों नहीं करना चाहिए, उदा। सामान्य लिस्प में '+ नाम +'। – Mars

+0

^^ का उपयोग करना: 2 प्रभाव है। (1) यह है कि संकलक मूल्य को रेखांकित करेगा, और var का उपयोग नहीं करेगा ताकि आप var के परिवर्तन या दुरुपयोग के प्रति प्रतिरोधी हों। (2) बस दस्तावेज है; लेखक दावा कर रहे हैं कि मूल्य * कभी नहीं बदला जाना चाहिए। –

+0

@ मर्स मेरा मानना ​​है कि स्टाइल गाइड का मतलब है कि वोर को स्थिर माना जाना चाहिए, क्योंकि क्लोजर में, इसे सेट के बाद एक Var के मूल मान को बदलने के लिए निराश किया जाता है। एक बार जो बदलता है, आमतौर पर एक गतिशील Var होगा, और earmuffs से घिरा हुआ होगा। तो 'नाम' निरंतर माना जाएगा (जैसा कि इसमें कभी भी नहीं बदलेगा, संकलक अनुकूलन या गारंटी के रूप में नहीं), और '* नाम *' को निरंतर माना जाएगा। जबकि '^: const' सिर्फ संकलक को इंगित करने के लिए है कि उसे var के उपयोग को रेखांकित करके कोड को अनुकूलित करना चाहिए। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^