2012-06-14 15 views
11

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

(def v (lazy-var (fn [] (do (println "REALLY EXPENSIVE FUNCTION") true)))) 

और भविष्य में, जब मैं या तो सिर्फ वर वी का उपयोग करें, या @v कहते हैं, मैं तो यह "है महंगा फंक्शन" बाहर मुद्रित करने के लिए मिलता है, और वी उस पर से सच का एक मूल्य है। यहां महत्वपूर्ण बात यह है कि एफएन का मूल्यांकन तब तक नहीं किया गया जब तक वेरिएबल (डी) संदर्भित नहीं किया गया। जब आवश्यक हो, तो फ़ंक्शन का मूल्यांकन एक बार और वैरिएबल के मान की गणना करने के लिए केवल एक बार किया जाता है। क्या यह क्लोजर में संभव है?

उत्तर

25

delay इस आवेदन के लिए एकदम सही होगा:

delay- (delay & body)

भाव की एक संस्था का उपयोग करके (एक देरी उद्देश्य यह है कि शरीर केवल पहली बार यह मजबूर किया जाता है लागू करेगा पैदावार के साथ force या deref/@), और परिणाम कैश करेगा और इसे बाद में force कॉल पर वापस कर देगा।

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

(def db (delay (println "DB stuff") x)) 

(select @db ...) ; "DB stuff" printed, x returned 
(insert @db ...) ; x returned (cached) 
+1

गीज़, मैं इसे देखने की कोशिश करते समय उस शब्द के बारे में क्यों नहीं सोचा? –

6

Clojure 1.3 की शुरुआत की इस उद्देश्य के लिए memoize समारोह:

(memoize च)

एक referentially पारदर्शी समारोह की एक memoized संस्करण देता है। फ़ंक्शन का ज्ञापन संस्करण परिणामों से तर्कों के कैश को रखता है और जब एक ही तर्क के साथ कॉल बार-बार दोहराया जाता है, तो उच्च स्मृति उपयोग की कीमत पर उच्च प्रदर्शन होता है।

अपने उदाहरण में memoize के साथ गैर मौजूदा आलसी-वर की जगह:

(def v (memoize (fn [] (do (println "REALLY EXPENSIVE FUNCTION") true)))) 
(v) 
=>REALLY EXPENSIVE FUNCTION 
=>true 
(v) 
=>true 

(देरी expr) भी काम करता है के रूप में एक और उत्तर बताते हैं। देरी को संदर्भित करने पर एक अतिरिक्त टिप्पणी - बल और डेफ/@ के बीच का अंतर यह है कि यदि गैर-विलंब चर पर उपयोग किया जाता है तो वह बल अपवाद नहीं फेंकता है जबकि deref/@ क्लासकास्टएक्सप्शन को फेंक सकता है "clojure.lang.IDeref पर नहीं डाला जा सकता"।

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