2013-03-21 7 views
15

उदाहरण निम्नलिखित पर विचार करें: जबकि safeMapM (GHC 7.6.1 का उपयोग कर -O2 के साथ) ठीक से काम करने लगता हैमानचित्र का उपयोग कर रहा है/अनुक्रम अच्छा अभ्यास माना जाता है?

safeMapM f xs = safeMapM' xs [] 
    where safeMapM' []  acc = return $ reverse acc 
      safeMapM' (x:xs) acc = do y <- f x 
            safeMapM' xs (y:acc) 

mapM return largelist  -- Causes stack space overflow on large lists 
safeMapM return largelist -- Seems to work fine 

mapM का उपयोग करते हुए बड़ी सूची पर एक ढेर अंतरिक्ष अतिप्रवाह कारण बनता है। हालांकि मैं हास्केल मानक पुस्तकालयों में safeMapM के समान फ़ंक्शन नहीं ढूंढ पाया।

क्या यह अभी भी mapM (या उस मामले के लिए sequence) का उपयोग करने के लिए अच्छा अभ्यास माना जाता है?
यदि हां, तो क्यों यह ढेर अंतरिक्ष अतिप्रवाह के खतरे के बावजूद अच्छा अभ्यास माना जाता है?
जो विकल्प नहीं यदि आप उपयोग करने के लिए सुझाव है कि करते हैं?

+0

शायद 'मैपएम' तेज है अगर यह अधिक नहीं होता है क्योंकि आपको' रिवर्स 'नहीं करना पड़ता है? क्या आपने इसे माप लिया? –

+0

क्या आप 'मेन' ​​मॉड्यूल पोस्ट कर सकते हैं जिसका उपयोग आपने परीक्षण किया था? – jberryman

+4

इसके अलावा, मोनैड हैं (जैसे 'Control.Monad.State.Lazy') जहां कुछ' 100 <$> मैपएम आईडी [1 ..] 'समाप्त होता है। '100 <$> सुरक्षित मैपएम आईडी [1 ..]' मोनाड –

उत्तर

9

निकलास बी के रूप में, mapM के अर्थशास्त्र एक प्रभावशाली दाहिने गुना के हैं, और यह फ़्लिप किए गए संस्करण की तुलना में अधिक मामलों में सफलतापूर्वक समाप्त हो जाता है। सामान्य तौर पर, mapM, और अधिक समझ में आता है के रूप में यह दुर्लभ है कि हम डेटा का एक विशाल सूची में एक परिणाम उपज नक्शा क्या करना चाहते हैं। अधिक सामान्यतः, हम प्रभाव के लिए इस तरह के एक सूची का मूल्यांकन करना चाहते कर देंगे, और उस मामले mapM_ और sequence_ है, जो दूर परिणाम फेंक में, क्या सिफारिश कर रहे हैं आम तौर पर कर रहे हैं।

संपादित करें: दूसरे शब्दों में, सवाल में उठाया मुद्दा बावजूद हाँ, mapM और sequence आमतौर पर इस्तेमाल किया जाता है और आम तौर पर अच्छा अभ्यास माना जाता है।

+1

मैं चाहता हूं कि मेरे कोड सभी मामलों में चलें, न केवल "अधिक मामलों" में। और बहुत सारे प्रभाव वापसी मूल्यों के साथ आते हैं उदा। उपयोगकर्ता का निवेश। निकलास बी उदाहरण मैं विकास करते समय पकड़ सकता हूं, बड़ी सूचियों के साथ अंतरिक्ष ओवरफ्लो ढेर परिनियोजन के बाद हो सकता है। Imho – jonnydee

+2

खोजने के लिए बहुत मुश्किल है विभिन्न अर्थशास्त्र और विभिन्न ट्रेडऑफ हैं। तो आपको अपनी स्थिति के अनुरूप एक चुनने की जरूरत है। यही जवाब है! एकमात्र जवाब! आपके द्वारा प्रदान किया जाने वाला दूसरा कोड पर्याप्त रूप से बड़ी सूचियों पर असफल हो जाएगा - यह केवल बड़ी सूचियां लेगा। आप प्रोग्राम में केवल स्टैक स्पेस भी जोड़ सकते हैं। बस, आप जानते हैं, ट्रेडऑफ समझते हैं और फिर एक विकल्प बनाते हैं। – sclv

6

यदि हां, तो स्टैक स्पेस ओवरफ़्लो के खतरे के बावजूद इसे अच्छा अभ्यास क्यों माना जाता है? यदि आप किस विकल्प का उपयोग करने के लिए सुझाव नहीं देते हैं?

आप के रूप में वे उत्पन्न कर रहे हैं सूची तत्वों पर कार्रवाई चाहते हैं, या तो pipes या conduit का उपयोग करें। दोनों कभी मध्यवर्ती सूची नहीं बनाएंगे।

मैं, pipes तरीका देख सकेंगे के बाद से है कि मेरे पुस्तकालय है। मैं पहली बार उपयोगकर्ता इनपुट से IO इकाई में उत्पन्न संख्या की एक अनंत सूची के साथ शुरू करेंगे:

import Control.Proxy 

infiniteInts :: (Proxy p) =>() -> Producer p Int IO r 
infiniteInts() = runIdentityP $ forever $ do 
    n <- lift readLn 
    respond n 

अब, मैं उन्हें प्रिंट के रूप में वे उत्पन्न कर रहे हैं चाहते हैं।

printer :: (Proxy p) =>() -> Consumer p Int IO r 
printer() = runIdentityP $ forever $ do 
    n <- request() 
    lift $ print n 

अब मैं Producer और Consumer का उपयोग कर (>->) कनेक्ट कर सकते हैं, और परिणाम runProxy का उपयोग कर चलाएँ::

>>> runProxy $ infiniteInts >-> printer 
4<Enter> 
4 
7<Enter> 
7 
... 

यही तो उपयोगकर्ता से Int रों पढ़ा जाएगा और गूंज यह एक नीचे की ओर हैंडलर को परिभाषित करने की आवश्यकता है उन्हें कंसोल पर वापस ले जाएं क्योंकि वे स्मृति में एक से अधिक तत्वों को सहेजे बिना उत्पन्न किए जाते हैं।

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

आप pipes के बारे में अधिक जानने के लिए चाहते हैं, तो मैं reading the tutorial सलाह देते हैं।

+0

यह उत्तर थोड़ा पुराना है। आप इसे अपडेट करना चाह सकते हैं। – dfeuer

-1

यदि आप आलसी शिविर में रहना चाहते हैं, तो lazyio पैकेज आपको इनपुट सूची को आलसी रूप से संसाधित करने की अनुमति देता है।

mapM f 

के बजाय आप

import qualified System.IO.Lazy as LazyIO 

LazyIO.run . mapM (LazyIO.interleave . f) 

कोई ढेर अतिप्रवाह अब लिखें।

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

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