2013-06-25 4 views
12

में 'यादृच्छिक' फ़ंक्शन को समझने का प्रयास करने के बाद मैंने अभी random फ़ंक्शन के बारे में सीखा।हास्केल

मेरी समझ के लिए, random फ़ंक्शन प्रकार का मान लेता है जो RandomGen का एक उदाहरण है और एक यादृच्छिक मान देता है जिसका मूल्य हम निर्दिष्ट कर सकते हैं। दूसरी तरफ, mksdGenInt लेता है और एक यादृच्छिक जनरेटर उत्पन्न करता है जो random फ़ंक्शन की ज़रूरत है।

मैं यादृच्छिक Bool मान उत्पन्न करने की कोशिश कर रहा था। ऐसा करने के लिए, मैंने एक समारोह randomBool बनाया।

randomBool :: Int -> Bool 
randomBool = fst . random . mkStdGen 

तो मैं कम संख्या के साथ False रों तुलना में बहुत अधिक True रों पाया। और मैं इसके बारे में उत्सुक था और

> length $ takeWhile randomBool [1..] 
53667 

निम्नलिखित के रूप में जाँच की पहली 53,667 धनात्मक पूर्णांक, random . mkStdGen रिटर्न True है, जो मेरे लिए बहुत यादृच्छिक होने लगते हैं नहीं है के लिए है कि मैं इसका मतलब यह है लगता है। क्या यह बहुत सामान्य है? या क्या मैं कुछ गलत कर रहा हूं जो True अधिक आसानी से होता है?

उत्तर

2

mkStdGen द्वारा निर्मित एक यादृच्छिक जनरेटर आवश्यक रूप से यादृच्छिक मान उत्पन्न नहीं करता है। अगली यादृच्छिक संख्या उत्पन्न करने के लिए, पिछले random कॉल द्वारा लौटाए गए यादृच्छिक जनरेटर का उपयोग करें।

उदाहरण के लिए, यह कोड 10 Bool एस उत्पन्न करता है।

take 10 $ unfoldr (Just . random) (mkStdGen 1) :: [Bool] 
+9

इस पर विस्तार से बता दें मदद करता है: यादृच्छिक जनरेटर एक है करने के लिए गारंटी नहीं है बीज मूल्यों पर यादृच्छिक वितरण, लेकिन यह उत्पादित मूल्यों के अनुक्रमों पर एक यादृच्छिक वितरण देने की गारंटी है। – mange

16

अनौपचारिक रूप से, जब आप बीज कि करीब हैं के साथ mkStdGen फोन एक साथ आप दो 'समान' जनरेटर मिल जाएगा। आपके उदाहरण में आप वास्तव में आपूर्ति किए गए प्रत्येक बीज के लिए नए जेनरेटर बना रहे हैं, और चूंकि वे बीज 1, 2, 3 इत्यादि हैं, इसलिए वे समान धाराएं उत्पन्न करेंगे।

जब आप एक जनरेटर के साथ random कहते हैं, आप वास्तव में वापस एक नया जनरेटर जोड़ी का दूसरा तत्व में मिलता है:

Prelude System.Random> random (mkStdGen 100) :: (Bool, StdGen) 
(True,4041414 40692) 

तो एक अच्छा विचार random करने के लिए अपने अगले कॉल के लिए यह प्रदान की जनरेटर का उपयोग करने के लिए है । अर्थात, और

Prelude System.Random> let (i, gen0) = random (mkStdGen 100) :: (Bool, StdGen) 
Prelude System.Random> let (j, gen1) = random gen0   :: (Bool, StdGen) 
Prelude System.Random> let (k, gen2) = random gen1   :: (Bool, StdGen) 
Prelude System.Random> (i, j, k) 
(True, False, False) 

तो यादृच्छिक मान का एक समूह बनाने के लिए, आप राज्य के रूप में जनरेटर पास करना चाहते हैं। आप एक State इकाई या कुछ और के माध्यम से मैन्युअल इस सेट कर सकते हैं, या बस randoms समारोह है, जो आप के लिए जनरेटर राज्य गुजर हैंडल का उपयोग करें: आप विशेष रूप से IO में होने के बारे में परवाह नहीं है तो

Prelude System.Random> take 10 $ randoms (mkStdGen 100) :: [Bool] 
[True,False,False,False,False,True,True,False,False,True] 

(ऐसा होता है) आप randomIO उपयोग कर सकते हैं:

Prelude System.Random> import Control.Monad 
Prelude System.Random Control.Monad> replicateM 10 randomIO :: IO [Bool] 
[True,True,False,True,True,False,False,False,True,True] 

LYAH की This section एक उपयोगी पढ़ने हो सकता है।

+0

आपके उत्तर के लिए धन्यवाद। मैं वास्तव में LYAH पढ़ने के बाद इस सवाल के साथ आया जहां मैंने पाया कि लगभग सभी मामलों में पहला सिक्का 'सत्य' है। (जब मैंने पहले कुछ हजारों मामलों की जांच की, तो मुझे 'झूठी' की तुलना में बहुत अधिक 'सत्य' मिला) एचएम ... भले ही 'करीबी' बीज 'समान' जेनरेटर उत्पन्न करते हैं, फिर भी मुझे लगता है कि यह अजीब है कि 'ट्रू' शो एक पंक्ति में 50 हजार संख्याओं के लिए ... – Tengu

+1

समस्या यह है कि 1-50000 से बीजित उन 50000 जनरेटर इतने समान हैं कि प्रत्येक उत्पाद का पहला तत्व 'सत्य' है। एक जेनरेटर का निरीक्षण करने के लिए 'यादृच्छिक (mkStdGen 100000) :: (बूल, StdGen)' का प्रयास करें जो प्रारंभ में 'गलत' उत्पन्न करता है। कुंजी यह है कि आपको वास्तव में केवल वही * बीज * एक ही जनरेटर होना चाहिए, बल्कि बीज के समान जनरेटर के समूह का समूह होना चाहिए। आप जो भी बीज चाहते हैं उसका प्रयोग करें, लेकिन फिर अतिरिक्त यादृच्छिक मूल्यों का उत्पादन करने के लिए 'जेनरेट जेनरेटर' का उपयोग करें। – jtobin

3

कंप्यूटर निर्धारक हैं और यादृच्छिक संख्या उत्पन्न नहीं कर सकते हैं। इसके बजाय, वे गणितीय सूत्रों पर भरोसा करते हैं जो यादृच्छिक दिखने वाली संख्याओं का वितरण वापस करते हैं।इन्हें छद्म-यादृच्छिक संख्या जेनरेटर कहा जाता है। हालांकि, निर्धारणा के कारण, हमें समस्या है कि यदि हम अपने कार्यक्रम के प्रत्येक आमंत्रण के दौरान इन सूत्रों को उसी तरह से चलाते हैं, तो हमें वही यादृच्छिक संख्या जेनरेटर मिलेंगे। जाहिर है, यह कोई अच्छा नहीं है, क्योंकि हम चाहते हैं कि हमारी संख्या यादृच्छिक हो! इस प्रकार, हमें यादृच्छिक जनरेटर को प्रारंभिक बीज मान प्रदान करना होगा जो रन-टू-रन से बदलता है। अधिकांश लोगों के लिए (यानी, वे क्रिप्टोग्राफिकल सामान नहीं कर रहे हैं), यादृच्छिक संख्या जेनरेटर वर्तमान समय से बीजित होता है। हास्केल में, यह छद्म-यादृच्छिक जनरेटर StdGen प्रकार द्वारा दर्शाया गया है। mkStdGen फ़ंक्शन का उपयोग बीज के साथ यादृच्छिक संख्या जेनरेटर बनाने के लिए किया जाता है। सी के विपरीत, जहां एक वैश्विक यादृच्छिक संख्या जेनरेटर है, हास्केल में, आप जितना चाहें उतना हो सकते हैं, और आप उन्हें विभिन्न बीजों के साथ बना सकते हैं।

हालांकि, एक चेतावनी है: चूंकि संख्या छद्म-यादृच्छिक हैं, इसलिए कोई गारंटी नहीं है कि अलग-अलग बीजों के साथ यादृच्छिक संख्या जेनरेटर दूसरे नंबर की तुलना में यादृच्छिक दिखते हैं। इसका अर्थ यह है कि जब आप randomBool पर कॉल करते हैं और इसे लगातार बीज मान देते हैं, तो इस बात की कोई गारंटी नहीं है कि आपके द्वारा बनाए गए StdGen से प्राप्त संख्या StdGen की तुलना में यादृच्छिक है। यही कारण है कि आप लगभग 50000 True प्राप्त करते हैं।

वास्तव में यादृच्छिक दिखने वाले डेटा को प्राप्त करने के लिए, आपको उसी यादृच्छिक संख्या जनरेटर का उपयोग करना जारी रखना होगा। यदि आप देखते हैं, random हास्केल फ़ंक्शन में StdGen -> (a, StdGen) एक प्रकार है। चूंकि हास्केल शुद्ध है, random फ़ंक्शन एक यादृच्छिक संख्या जेनरेटर लेता है, एक छद्म-यादृच्छिक मान (वापसी मूल्य का पहला तत्व) उत्पन्न करता है और फिर एक नया StdGen देता है जो मूल बीज के साथ बीजित जनरेटर का प्रतिनिधित्व करता है, लेकिन एक देने के लिए तैयार है नया यादृच्छिक संख्या। यादृच्छिक डेटा प्राप्त करने के लिए आपको इसे अन्य StdGen को चारों ओर रखने और इसे अगले random फ़ंक्शन पर रखने की आवश्यकता है।

यहां एक उदाहरण है, तीन यादृच्छिक बूल, a, b, और c उत्पन्न करना।

randomBools :: StdGen -> (Bool, Bool, Bool) 
randomBools gen = let (a, gen') = random gen 
         (b, gen'') = random gen'' 
         (c, gen''') = random gen''' 
        in (a, b, c) 

सूचना कैसे gen चर "पिरोया" है यादृच्छिक करने के लिए कॉल के माध्यम से।

आप एक राज्य मोनड का उपयोग करके गुजरने वाले राज्य को सरल बना सकते हैं। उदाहरण के लिए,

import Control.Monad.State 
import System.Random 

type MyRandomMonad a = State StdGen a 

myRandom :: Random a => MyRandomMonad a 
myRandom = do 
    gen <- get -- Get the StdGen state from the monad 
    let (nextValue, gen') = random gen -- Generate the number, and keep the new StdGen 
    put gen' -- Update the StdGen in the monad so subsequent calls generate new random numbers 
    return nextValue 

अब आप randomBools समारोह लिख सकते हैं:

randomBools' :: StdGen -> (Bool, Bool, Bool) 
randomBools' gen = fst $ runState doGenerate gen 
    where doGenerate = do 
      a <- myRandom 
      b <- myRandom 
      c <- myRandom 
      return (a, b, c) 

आप Bool रों की (परिमित) सूची उत्पन्न करना चाहते हैं, तो आप

randomBoolList :: StdGen -> Int -> ([Bool], StdGen) 
randomBoolList gen length = runState (replicateM length myRandom) gen 

कर सकते हैं ध्यान दें कि हम वापस किए गए जोड़ी के दूसरे तत्व के रूप में StdGen को वापस कैसे करते हैं, ताकि इसे नए कार्यों को दिया जा सके।

अधिक सरलता से, यदि आप StdGen से उसी प्रकार के यादृच्छिक मानों की अनंत सूची उत्पन्न करना चाहते हैं, तो आप randoms फ़ंक्शन का उपयोग कर सकते हैं। इसमें हस्ताक्षर (RandomGen g, Random a) => g -> [a] है। x के शुरुआती बीज का उपयोग करके Bool की अनंत सूची उत्पन्न करने के लिए, आप बस randoms (mkStdGen x) चलाते हैं। आप length $ takeWhile id (randoms (mkStdGen x)) का उपयोग करके अपना उदाहरण कार्यान्वित कर सकते हैं। आपको सत्यापित करना चाहिए कि x के विभिन्न प्रारंभिक मानों के लिए आपको अलग-अलग मान मिलते हैं, लेकिन यदि आप उसी x की आपूर्ति करते हैं तो हमेशा वही मान प्राप्त करें।

अंत में, यदि आपको IO मोनैड से बंधे होने की परवाह नहीं है, तो हास्केल भी एक वैश्विक यादृच्छिक संख्या जेनरेटर प्रदान करता है, जो अनिवार्य भाषाओं की तरह है। IO मोनैड में फ़ंक्शन randomIO को कॉल करने से आप जो कुछ भी पसंद करते हैं उसका यादृच्छिक मूल्य आपको प्रदान करेगा (जब तक यह कम से कम Random टाइपक्लास का उदाहरण है)। IO मोनैड को छोड़कर, आप इसे समान रूप से myRandom पर उपयोग कर सकते हैं। इसमें अतिरिक्त सुविधा है कि यह हास्केल रनटाइम द्वारा पूर्व-बीजित है, जिसका अर्थ है कि आपको StdGen बनाने की चिंता करने की आवश्यकता नहीं है। तो, IO इकाई में 10 Bool रों के एक यादृच्छिक सूची बनाने के लिए, तुम सब करने की ज़रूरत है replicateM 10 randomIO :: IO [Bool].

आशा इस :)

+0

कड़ाई से, कंप्यूटर _can_ यादृच्छिक संख्याएं उत्पन्न करते हैं यदि आपके पास उपयुक्त हार्डवेयर स्रोत है। नवीनतम इंटेल प्रोसेसर ने इस उद्देश्य के लिए एक मशीन कोड निर्देश भी जोड़ा ... (हां, यह केवल उस बिंदु से संबंधित है जो आप बनाने की कोशिश कर रहे थे।) – MathematicalOrchid