2016-09-09 3 views
10

मैं एक Producer कि मानों अनियमितता पर निर्भर बनाता है, मेरे अपने Random इकाई का उपयोग कर:आईओ एक्शन के साथ कुछ गैर-आईओ मोनैड में पाइप का स्वाभाविक रूप से और कुशलता से उपभोग कैसे कर सकता हूं?

newtype Random a = 
    Random (forall m. PrimMonad m => Gen (PrimState m) -> m a) 

runIO :: Random a -> IO a 
runIO (Random r) = MWC.withSystemRandom (r @ IO) 

:

policies :: Producer (Policy s a) Random x 

Randommwc-random पर एक आवरण है कि ST या IO से चलाया जा सकता है policies उत्पादक एक सरल सुदृढ़ीकरण सीखने एल्गोरिदम से बेहतर और बेहतर नीतियां पैदा करता है।

मैं कुशलता से करने के बाद नीति प्लॉट कर सकते हैं, कहते हैं, 5,000,000 पुनरावृत्तियों policies में अनुक्रमण द्वारा:

Just convergedPolicy <- Random.runIO $ Pipes.index 5000000 policies 
plotPolicy convergedPolicy "policy.svg" 

मैं अब हर 500,000 सीढ़ियों पर मध्यवर्ती नीतियों प्लॉट करने के लिए देखने के लिए कि वे किस तरह अभिसरण चाहते हैं। मैंने कुछ कार्यों को लिखा है जो policies निर्माता लेते हैं और कहते हैं, 10 नीतियां- प्रत्येक 500,000 पुनरावृत्तियों में से एक सूची ([Policy s a]) निकालें- और फिर उन सभी को साजिश दें।

हालांकि, इन कार्यों में अब तक की अंतिम नीति को साजिश करने की तुलना में अधिक लंबा (10x) और अधिक मेमोरी (4x) का उपयोग करें, भले ही सीखने के पुनरावृत्तियों की कुल संख्या समान हो (यानी 5,000,000)। मुझे लगता है कि यह कचरा कलेक्टर बाधा एक सूची निकालने की वजह से है, और इस पाइप के unidiomatic उपयोग हो रहा है:

मुहावरेदार पाइप शैली तत्वों तुरंत खपत के रूप में वे बजाय स्मृति में सभी तत्वों को लोड करने की उत्पन्न कर रहे हैं ।

इस तरह एक पाइप लेने जब Producer कुछ यादृच्छिक इकाई (यानी Random) और प्रभाव मैं उत्पादन करना चाहते हैं IO में है खत्म हो गया है करने के लिए सही दृष्टिकोण क्या है?

एक और तरीका रखो, मैं Producer (Policy s a) Random x को Consumer (Policy s a) IO x में प्लग करना चाहता हूं।

+0

क्या 'यादृच्छिक' के पास 'मोनाडियो' उदाहरण है? यदि ऐसा है, तो आपके पास 'उछाल लिफ्टियो :: उपभोक्ता (पॉलिसी एस) आईओ एक्स -> उपभोक्ता (पॉलिसी एस) रैंडम एक्स' होगा। इसके बारे में जाने के अन्य तरीके हैं, कुछ तेज हो सकते हैं, लेकिन यह 'यादृच्छिक' के बारे में अधिक जानने में मदद कर सकता है। – Michael

+1

@ माइकल: ऐसा नहीं है, और मैं इसे नहीं चाहता। यह केवल यादृच्छिकता और * नहीं * सामान्य आईओ कर सकता है। आदर्श रूप में, मुझे एक समाधान पसंद आएगा जो केवल इस तथ्य पर निर्भर करता है कि 'रैंडम' में 'runIO :: रैंडम ए -> आईओ ए' फ़ंक्शन है। –

+1

और मुझे लगता है कि आप 'निर्माता (पॉलिसी एस) रैंडम एक्स' को 'निर्माता (पॉलिसी एस) आईओ एक्स' में बदलने के लिए 'उछाल चलाने वाले' को नहीं चाहते हैं क्योंकि यादृच्छिकता उत्पन्न होती है। – Michael

उत्तर

2

Random एक पाठक है कि एक जनरेटर

import Control.Monad.Primitive 
import System.Random.MWC 

newtype Random a = Random { 
    runRandom :: forall m. PrimMonad m => Gen (PrimState m) -> m a 
} 

हम तुच्छता से एक ReaderT (Gen (PrimState m)) m a में एक Random a परिवर्तित कर सकते हैं पढ़ता है। यह तुच्छ ऑपरेशन वह है जिसे आप Producer ... Random a को Producer ... IO a में बदलने के लिए चाहते हैं।

import Control.Monad.Trans.Reader 

toReader :: PrimMonad m => Random a -> ReaderT (Gen (PrimState m)) m a 
toReader = ReaderT . runRandom 

toReader के बाद से hoist से किसी भी यादृच्छिक पीढ़ी भूमि के ऊपर यह ing नहीं होगी तुच्छ है। यह फ़ंक्शन केवल इसके प्रकार के हस्ताक्षर को प्रदर्शित करने के लिए लिखा गया है।

import Pipes 

hoistToReader :: PrimMonad m => Proxy a a' b b' Random       r -> 
           Proxy a a' b b' (ReaderT (Gen (PrimState m)) m) r 
hoistToReader = hoist toReader 

यहां लेने के दो दृष्टिकोण हैं। सरल दृष्टिकोण hoist आपके Consumer एक ही मोनैड में है, पाइप को एक साथ लिखें, और उन्हें चलाएं।

type ReadGenIO = ReaderT GenIO IO 

toReadGenIO :: MFunctor t => t Random a -> t ReadGenIO a 
toReadGenIO = hoist toReader 

int :: Random Int 
int = Random uniform 

ints :: Producer Int Random x 
ints = forever $ do 
    i <- lift int 
    yield i 

sample :: Show a => Int -> Consumer a IO() 
sample 0 = return() 
sample n = do 
    x <- await 
    lift $ print x 
    sample (n-1) 

sampleSomeInts :: Effect ReadGenIO() 
sampleSomeInts = hoist toReader ints >-> hoist lift (sample 1000) 

runReadGenE :: Effect ReadGenIO a -> IO a 
runReadGenE = withSystemRandom . runReaderT . runEffect 

example :: IO() 
example = runReadGenE sampleSomeInts 

Pipes.Lift में उपकरण का एक और सेट है कि पाइप के उपयोगकर्ताओं के बारे में पता होना चाहिए नहीं है। ये Random मोनैड जैसे Proxy पर वितरित करके ट्रांसफॉर्मर चलाने के लिए टूल हैं। ट्रांसफार्मर लाइब्रेरी से परिचित ट्रांसफार्मर चलाने के लिए यहां प्री-बिल्ट टूल्स हैं। वे सभी distribute से बने हैं। यह Proxy ... (t m) a को t (Proxy ... m) a में बदल देता है जिसे आप चला सकते हैं जो भी टूल्स आप t चलाने के लिए उपयोग करते हैं।

import Pipes.Lift 

runRandomP :: PrimMonad m => Proxy a a' b b' Random r -> 
          Gen (PrimState m) -> Proxy a a' b b' m r 
runRandomP = runReaderT . distribute . hoist toReader 

आप पाइप एक साथ संयोजन समाप्त कर सकते हैं और runEffect का उपयोग Proxy रों से छुटकारा पाने के लिए, लेकिन आप जनरेटर तर्क से खेल होगी खुद के रूप में आप गठबंधन Proxy ... IO r एक साथ है।

+0

से स्पष्ट हो जाता है बस इसे लागू करने के लिए चारों ओर मिल गया, और मुझे निश्चित रूप से यह समाधान पसंद है। धन्यवाद! –

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

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