2011-03-08 17 views
12

कम करें और कटौती आपको अनुक्रम पर राज्य जमा करने दें। अनुक्रम में प्रत्येक तत्व तक संचित स्थिति को संशोधित करेगा, अनुक्रम का अंत तक पहुंच जाएगा।क्लोजर: कम करें, कटौती और अनंत सूचियां

असीमित सूची को कम करने या घटाने के प्रभाव क्या हैं?

(def c (cycle [0])) 
(reduce + c) 

यह जल्दी से आउटऑफमेमरी एरर फेंक देगा। वैसे, (reduce + (cycle [0])) एक आउटऑफमेमरी त्रुटि नहीं फेंकता है (कम से कम उस समय के लिए नहीं जब तक मैं इंतजार कर रहा था)। यह कभी वापस नहीं आता है। यकीन नहीं है कि क्यों।

क्या असीमित सूची को कम करने या घटाने के तरीके को समझने का कोई तरीका है जो समझ में आता है? उपर्युक्त उदाहरण में जो समस्या मैं देखता हूं, वह है कि अंततः सूची का मूल्यांकन हिस्सा ढेर को बहने के लिए काफी बड़ा हो जाता है। शायद एक अनंत सूची सही प्रतिमान नहीं है। जनरेटर, आईओ स्ट्रीम, या एक इवेंट स्ट्रीम को कम करने से अधिक समझदारी होगी। मूल्यांकन के मूल्यांकन के बाद मूल्य को नहीं रखा जाना चाहिए और राज्य को संशोधित करने के लिए उपयोग किया जाना चाहिए।

उत्तर

15

यह कभी वापस नहीं आएगा क्योंकि एक अनुक्रम और एक समारोह लेता है और तक फ़ंक्शन लागू करता है इनपुट अनुक्रम खाली होता है, केवल तभी यह पता चल सकता है कि इसका अंतिम मूल्य है।

वास्तव में अनंत सीक पर कम करना बहुत समझ में नहीं आता है जब तक कि यह अपनी प्रगति को लॉगिंग करने जैसे साइड इफेक्ट का उत्पादन नहीं कर रहा हो।

आपके पहले उदाहरण में आप पहले एक अनंत अनुक्रम को संदर्भित करते हुए एक var बना रहे हैं।

(def c (cycle [0])) 

फिर आप var c की सामग्री को पार कर रहे हैं जिससे कम करने के लिए तत्वों को पढ़ना शुरू हो जाता है।

(reduce + c) 

इन तत्वों को कचरा एकत्र नहीं किया जा सकता क्योंकि वर ग उनमें से पहले, जो बारी में दूसरे और इतने पर के लिए एक संदर्भ रखती है के लिए एक संदर्भ रखती है। अंततः यह वहाँ है ढेर में अंतरिक्ष और फिर यह OOM के रूप में कई पढ़ता है।

अपने दूसरे उदाहरण में ढेर उड़ाने से रोकने के लिए आप पहले से उपयोग किए गए डेटा का संदर्भ नहीं रख रहे हैं, इसलिए चक्र द्वारा लौटाए गए सीक पर आइटम जीसीडी जितनी जल्दी हो सके उतने ही होते हैं और संचित परिणाम जारी रहता है बडे बनो। अंततः यह एक लंबी और दुर्घटना (clojure 1.3) अतिप्रवाह होगा या एक BigInteger करने के लिए स्वयं को बढ़ावा देने और सब ढेर (clojure 1,2)

(reduce + (cycle [0])) 
+0

धन्यवाद। समझ में आता है। पहले मामले में, मैं पहले सी को कॉल कर सकता हूं और वह अनंत सूची में पहले तत्व का मूल्यांकन करेगा, जो स्मृति में रहेगा। अगर मैं पहले पर्याप्त समय कहता हूं, तो अनंत सूची का मूल्यांकन हिस्सा बहुत बड़ा हो जाएगा और ढेर बह जाएगा। दूसरे मामले में मूल्यांकन किया गया हिस्सा लगातार फेंक दिया जाता है। वैसे, दूसरे मामले में, ढेर कभी नहीं बह जाएगा क्योंकि शून्य का योग अभी भी शून्य है। – yalis

+0

शून्य बिट पर अच्छा बिंदु। कि clojure का उल्लेख करने के लिए मैं अपनी अच्छी लगता है कि गलत :) –

11

आर्थर की जवाब है, के रूप में यह हो जाता है जहाँ तक अच्छी है, लेकिन यह के आकार के बढ़ने दिखता है जैसे वह reductions के बारे में अपने दूसरे प्रश्न का समाधान नहीं करता। reductions यदि एक सूची केवल एन तत्वों लंबे दी क्या reduceहोगा वापस आ गए के मध्यवर्ती चरणों में से एक आलसी अनुक्रम देता है। तो यह एक अनंत सूची पर reductions कॉल करने के लिए पूरी तरह से समझदार है:

user=> (take 10 (reductions + (range))) 
(0 1 3 6 10 15 21 28 36 45) 
+1

होने के लिए लेकिन यहाँ आपको धीरे-धीरे ढेर अतिप्रवाह जाएगा 1.2 और 1.3 इस संबंध में अलग हैं चाहता था। कटौती एक आलसी सूची लौटाती है, लेकिन लाखों तत्वों का उपयोग करने के लिए, आपको पहले मिलियन तत्वों का मूल्यांकन करना होगा, जो ढेर को बहती हैं। – yalis

+2

असल में, इसे वापस ले लो। आप पहले तत्व को छोड़कर, अगली कॉलिंग जारी रख सकते हैं और शेष सूची को सहेज सकते हैं। आलसी दृश्यों के बारे में तर्क मुश्किल व्यवसाय है। – yalis

+0

ओह यह है कि सामान जोड़ने के लिए धन्यवाद। किसी भी आलसी अनुक्रम के साथ के रूप में अपने सिर ढीला कर लें;) –

2

आप एक आईओ धारा की तरह एक सूची से आइटम हो रही रखने के लिए और रन के बीच राज्य रखना चाहते हैं, तो आप का सहारा के बिना doseq (उपयोग नहीं कर सकते डीईएफ़ के)।इसके बजाय एक अच्छा दृष्टिकोण पाश उपयोग करने के लिए/पुनरावृत्ति होना यह आप लेने वाली बहुत ज्यादा ढेर अंतरिक्ष से बचने के लिए अनुमति देगा हो सकता है और आप राज्य रख दूँगी आपके मामले में,:

(loop [c (cycle [0])] 
    (if (evaluate-some-condition (first c)) 
    (do-something-with (first c) (recur (rest c))) 
    nil)) 
बेशक

अपने मामले की तुलना में नहीं है यहां एक शर्त जांचें कि यह सुनिश्चित करने के लिए कि हम अनिश्चित काल तक लूप नहीं करते हैं।

+0

आप शायद कुछ राज्य में पारित करने के लिए कम करने अनुकरण करना चाहते हैं। (पाश [ग (चक्र [0]) राज्य() ((का मूल्यांकन-कुछ शर्त (पहली ग)) (पुनरावृत्ति होना (बाकी ग) क्या कुछ-साथ अगर (प्रथम (ग) राज्य)) राज्य)) – yalis

+1

Pyr के संस्करण संकलन नहीं होगा, जब तक कि 'क्या कुछ-with' पूंछ की स्थिति में वास्तव में * उस मैक्रो रूप है जो' में recur' है में विस्तारित है *। – amalloy

0

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

स्थिति के इस प्रकार के लिए एक विकल्प के रूप में, यहाँ एक उपयोगी समारोह है कि एक दृश्य में केवल पहले n आइटम को कम कर देता है, उचित दक्षता के लिए पुनरावृत्ति होना का उपयोग कर लागू किया:

(defn counted-reduce 
    ([n f s] 
    (counted-reduce (dec n) f (first s) (rest s))) 
    ([n f initial s] 
    (if (<= n 0) 
     initial 
     (recur (dec n) f (f initial (first s)) (rest s))))) 

(counted-reduce 10000000 + (range)) 
=> 49999995000000 
+0

या आप उपयोग कर सकते हैं (n वें (कटौती + (रेंज)) 9999999) – yalis

+0

बिल्कुल सच। गिना-कम थोड़ा तेज प्रदर्शन करता है (~ biggish n के लिए मेरी मशीन पर ~ 30%)। बिल्कुल यकीन नहीं है क्यों .... लेकिन शायद आलसी चक्करदार सीक के लिए अतिरिक्त ओवरहेड की वजह से कटौती? – mikera

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