2013-01-07 15 views
13

प्राप्त करें मैं यादृच्छिक संख्या उत्पन्न करने के लिए System.Random और Random टाइपक्लास का उपयोग कर रहा हूं। हालांकि मैं एक नया जनरेटर होने का बाधा के बिना की तरह randoms :: StdGen -> Int -> ([Float], StdGen)यादृच्छिक मानों की सूची जेनरेट करें और एक नया जनरेटर

एक समारोह के साथ मनमाना लंबाई के यादृच्छिक मंगाई की एक सूची उत्पन्न करना चाहते हैं, मैं आसानी से randoms gen n = (take n $ randoms gen) :: [Float]

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

मैं यादृच्छिक मूल्यों की एक अनंत (या मनमानी लंबाई) सूची कैसे उत्पन्न कर सकता हूं जबकि मेरे यादृच्छिक जनरेटर को "रीफ्रेशिंग" भी कर सकता हूं।

+1

एक और विकल्प ['split'] (http://hackage.haskell.org/packages/archive/random/latest/doc/html/System-Random.html#v:split) जेनरेटर दो में है। फिर आप परिणामी जेनरेटर में से एक को 'रैंडम्स' कॉल करने और दूसरे के साथ जारी रखने के लिए उपयोग कर सकते हैं। यह अनंत सूचियों के साथ भी काम करता है। – hammar

उत्तर

28

ठीक है, समारोह को देखो आप की क्या ज़रूरत है:

random :: StdGen -> (Float, StdGen) -- From System.Random 

हम State इकाई में इस लपेट स्टेटफुल गणना पाने के लिए कर सकते हैं:

state :: (s -> (a, s)) -> State s a -- From Control.Monad.Trans.State 

random' :: State StdGen Float 
random' = state random 

अब, हम एक गुच्छा उत्पन्न कर सकते हैं तैरता का सिर्फ replicateM का उपयोग कर:

replicateM :: (Monad m) => Int -> m a -> m [a] -- From Control.Monad 

randoms' :: Int -> State StdGen [Float] 
randoms' n = replicateM n random' 

अंत में, हम खोलने

randoms :: Int -> StdGen -> ([Float], StdGen) 
randoms n = runState (randoms' n) 

आप एक समारोह परिभाषा में इन सब जोड़ देते हैं तो आपको मिलेगा:: State स्पष्ट जनरेटर गुजर वापस पाने के लिए

randoms :: Int -> StdGen -> ([Float], StdGen) 
randoms n = runState (replicateM n (state random)) 

दूसरे शब्दों में, हम के रूप में प्रक्रिया का वर्णन कर सकते हैं:

State इकाई में
  • रैप random
  • यह दोहराने n बार
  • खोलने यह

यही कारण है कि monads इस तरह के एक महत्वपूर्ण अवधारणा है। मोनैड इंटरफेस के लेंस के माध्यम से देखे जाने पर चीजें जो पहली बार मुश्किल लगती हैं, सरल कंप्यूटेशंस होती हैं।

3

State या split बिना एक वैकल्पिक, (Data.Tuple से और swap) Data.List से mapAccumL का उपयोग कर:

nRandoms n gen = mapAccumL(\g _ -> swap $ random g) gen [1..n] 

हालांकि मैं मैं क्यों यह किसी भी बेहतर होना चाहिए के लिए एक ठोस तर्क नहीं है कहना है मार्ग।

+0

मानक पुस्तकालयों में 'स्वैप' है? –

+0

@ बेनमिलवुड 'डेटा टुपल '। हाल ही में जोड़ा गया था, मुझे याद नहीं है कि हाल ही में कैसे हाल ही में। देखा: ghc-7.0 में अपनी पहली उपस्थिति बनाई। *। तो बहुत हाल ही में नहीं। –

5

गेब्रियल का जवाब सही है और यह बहुत अधिक है कि कैसे MonadRandom पैकेज लागू किया गया है (एक यादृच्छिक जनरेटर के साथ पैरामीटर एक राज्य मोनाड)।

यह आपको हर बार परिभाषित करता है, और यह एक मोनाड ट्रांसफार्मर के साथ भी आता है, ताकि आप किसी अन्य मोनाड को उसमें परिवर्तित कर सकें जो यादृच्छिक मूल्य भी उत्पन्न कर सके।

आपका उदाहरण आसानी से लागू किया जा सकता है के रूप में:

(runRand $ take n `fmap` getRandoms) :: RandomGen g => g -> ([Int], g) 

StdGen RandomGen का का एक उदाहरण भी है, तो आप बस इसे प्लग और जा सकते हैं!

1

आप एक ऐसे फ़ंक्शन को परिभाषित कर सकते हैं जिसका प्रकार आप जो कहते हैं उससे मेल खाता है, हालांकि आम तौर पर।

import System.Random 

randoms' :: (RandomGen g, Random a) => g -> Int -> ([a], g) 
randoms' g n = 
    let (g1, g2) = split g 
    in (take n $ randoms g1, g2) 

हालांकि इसे इस्तेमाल करता है split

split :: g -> (g, g)

split आपरेशन एक दो अलग यादृच्छिक संख्या जनरेटर प्राप्त करने के लिए अनुमति देता है। यह कार्यात्मक कार्यक्रमों में बहुत उपयोगी है (उदाहरण के लिए, रिकर्सिव कॉल करने के लिए यादृच्छिक संख्या जेनरेटर पास करते समय), लेकिन split और नरक के सांख्यिकीय रूप से मजबूत कार्यान्वयन पर बहुत कम काम किया गया है;

यह अभी भी आप जो चाहते हैं वह नहीं करता है। (मैं आसान दृश्य तुलना के लिए नीचे दिए गए उदाहरण में Bool का उपयोग करें।)

ghci> g <- getStdGen 
ghci> randoms' g 5 :: ([Bool], StdGen) 
([False,False,False,True,False],1648254783 2147483398) 
ghci> randoms' g 5 :: ([Bool], StdGen) 
([False,False,False,True,False],1648254783 2147483398) 

ध्यान दें कि यादृच्छिक सरणियों ही हैं।

हालांकि यह कार्य जनरेटर को विभाजित करने की दिक्कत पर जाता है, हम तुरंत इसे त्याग देते हैं। इसके बजाय, अपने कोड IO इकाई में चल रहा है बाद में कॉल करने के लिए यह

ghci> let (a1,g2) = randoms' g 5 :: ([Bool], StdGen) 
ghci> let (a2,_) = randoms' g2 5 :: ([Bool], StdGen) 
ghci> (a1,a2) 
([False,False,False,True,False],[True,True,True,False,True] 

में के रूप में सूत्रण द्वारा g2 का इस्तेमाल करते हैं, तो आप उपयोग कर सकते हैं setStdGen

के रूप में, अंत में वैश्विक यादृच्छिक संख्या जनरेटर को बदलने के लिए
myAction :: Int -> IO ([Float],[Float]) 
myAction n = do 
    g <- getStdGen 
    let (f1,g2) = randoms' g n 
    let (f2,g3) = randoms' g2 n 
    setStdGen g3 
    return (f1, f2) 

आसपास के थ्रेडिंग राज्य अजीब और त्रुटि-प्रवण है। State या ST का उपयोग करने पर विचार करें यदि आपके पास बहुत सारे बार बॉयलरप्लेट हैं।