2011-12-07 16 views
17

में एक रेंज में एक यादृच्छिक पूर्णांक उत्पन्न करें मैं किसी भी बीज का उपयोग किये बिना किसी श्रेणी (ए, बी) से हास्केल में यादृच्छिक संख्या कैसे उत्पन्न कर सकता हूं?हास्केल

फ़ंक्शन को एक इंट वापस करना चाहिए और आईओ इंट नहीं करना चाहिए। मेरे पास एक फ़ंक्शन एक्स है जो लेता है और Int और अन्य तर्क और आउटपुट करता है जो आईओ नहीं है।

यदि यह संभव नहीं है, तो मैं टाइम लाइब्रेरी का उपयोग करके बीज कैसे उत्पन्न कर सकता हूं और mkStdGen के साथ सीमा में यादृच्छिक संख्या उत्पन्न कर सकता हूं?

किसी भी मदद की वास्तव में सराहना की जाएगी।

+1

http: // stackoverflow .com/a/2738824/570689 - इसी तरह के प्रश्न –

+4

के लिए अच्छा जवाब यह लगता है कि आप 'यादृच्छिक Int lo hi = lo' या उस तरह का कुछ है। किसी प्रकार के बीज या आईओ के बिना समारोह को हर बार एक ही मूल्य वापस करना पड़ता है। और निचली बाउंड किसी अन्य 'Int' के रूप में यादृच्छिक है। :) – augustss

+2

"कोई भी जो यादृच्छिक अंकों के उत्पादन के अंकगणितीय तरीकों को मानता है, निश्चित रूप से, पाप की स्थिति में है।" जॉन वॉन न्यूमैन _in_ Knuth, डी। _The Art of Computer Programming_, वॉल्यूम 2, पी। 1 (1 9 81)। – rickythesk8r

उत्तर

36

कोई फ़ंक्शन IO के बिना IO पर वापस नहीं लौटा सकता है, जब तक कि यह एक शुद्ध कार्य न हो, यानी एक ही इनपुट दिया जाता है, आपको हमेशा एक ही आउटपुट मिल जाएगा। इसका मतलब यह है कि यदि आप IO के बिना यादृच्छिक संख्या चाहते हैं, तो आपको एक बीज को तर्क के रूप में लेने की आवश्यकता होगी।

  • आप एक बीज लेने के लिए चुनते हैं, तो यह प्रकार StdGen का होना चाहिए, और आप randomR का उपयोग इसमें से एक संख्या उत्पन्न कर सकते हैं। नया बीज बनाने के लिए newStdGen का उपयोग करें (इसे IO में किया जाना होगा)।

    > import System.Random 
    > g <- newStdGen 
    > randomR (1, 10) g 
    (1,1012529354 2147442707) 
    

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

  • अन्यथा, आप एक यादृच्छिक संख्या आप के लिए सभी StdGen सामान का लिया देखभाल के साथ IO इकाई में सीधे प्राप्त करने के लिए, randomRIO उपयोग कर सकते हैं:

    > import System.Random 
    > randomRIO (1, 10) 
    6 
    
+6

ऐसा करने वालों के लिए, 'आयात प्रणाली' यादृच्छिक' मत भूलना! –

4

असुरक्षित के सभी प्रकार का सहारा के बिना प्रथाओं, IO Int या कुछ समान टाइप करने के बजाय इस तरह के फ़ंक्शन के लिए Int टाइप करना संभव नहीं है। Int प्रकार के कार्य (या, इस मामले में, स्थिरांक) शुद्ध हैं, जिसका अर्थ यह है कि हर बार जब आप फ़ंक्शन "निरंतर" प्राप्त करते हैं) तो आपको वही मान "लौटाया" प्राप्त करने की गारंटी दी जाती है।

यदि आप प्रत्येक आमंत्रण पर एक अलग, यादृच्छिक रूप से चुने गए मूल्य को वापस करना चाहते हैं, तो आपको IO -monad का उपयोग करने की आवश्यकता होगी।

कुछ अवसरों में, आप पूरे कार्यक्रम के लिए एक यादृच्छिक रूप से उत्पादित मूल्य चाहते हैं, यानी, प्रोग्राम के परिप्रेक्ष्य से, यह एक शुद्ध मूल्य के रूप में व्यवहार करता है। प्रत्येक बार जब आप प्रोग्राम के उसी भाग के भीतर मूल्य पूछते हैं, तो आपको वही मान वापस मिल जाता है। चूंकि पूरा कार्यक्रम अनिवार्य रूप से IO है-फिर आप उस मान को एक बार उत्पन्न कर सकते हैं और इसे पास कर सकते हैं, लेकिन यह थोड़ा बेकार महसूस कर सकता है। यह तर्क हो सकता है कि, इस स्थिति में, यह अभी भी सुरक्षित प्रकार Int के एक शीर्ष स्तर निरंतर साथ मूल्य सहयोगी और कहा कि लगातार निर्माण के लिए unsafePerformIO उपयोग करने के लिए है:

import System.IO.Unsafe -- be careful!           
import System.Random 

-- a randomly chosen, program-scoped constant from the range [0 .. 9]    
c :: Int 
c = unsafePerformIO (getStdRandom (randomR (0, 9))) 
+32

ऐसा मत करो !! – augustss

+4

विशेष रूप से, http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-IO-Unsafe.html पर उल्लिखित सलाह और सावधानी बरतने के बिना ऐसा न करें। –

+0

@ डीब्लेलिक्स आपका लिंक मर चुका है – Muhd

1
fmap yourFunctionX $ randomRIO (a, b) 

या

fmap (\x -> yourFunctionX aParam x anotherParam) $ randomRIO (a, b) 

परिणाम तब IO whateverYourFunctionXReturns का प्रकार होगा।

यदि आप import Control.Applicative, आप कह सकते हैं

yourFunctionX <$> randomRIO (a, b) 

या

(\x -> yourFunctionX aParam x anotherParam) <$> randomRIO (a, b) 

जो आप पा सकते हैं स्पष्ट

1

ध्यान दें कि आप आईओ इकाई का उपयोग कर यादृच्छिक मान की असीमित सूची प्राप्त कर सकते हैं और गैर-आईओ कार्यों में [Int] का उपयोग करें। इस तरह आपको बीज को अपने साथ ले जाने की ज़रूरत नहीं है, लेकिन फिर भी पाठ्यक्रम की सूची लेनी होगी। सौभाग्य से, इस तरह के थ्रेडिंग को सरल बनाने के लिए बहुत सारे सूची प्रसंस्करण कार्य हैं, और आप अभी भी जटिल मामलों में State मोनड का उपयोग कर सकते हैं।

यह भी ध्यान रखें कि आप आसानी से आईओ इंट को एक इंट में परिवर्तित कर सकते हैं। यदि foo एक आईओ इंट पैदा करता है, और बार अपनी ही पैरामीटर के रूप में एक इंट लेता है और एक गैर आईओ मान देता है, निम्न करेगा:

foo >>= return . bar 

या अंकन कर का उपयोग करते हुए:

do 
    a <- foo 
    return $ bar a 
0

मैं इस्तेमाल किया उस उद्देश्य के लिए SipHash

import Data.ByteArray.Hash 
import Data.ByteString (pack, cons) 
import Data.Word (Word8, Word64) 

random :: Word64 -> Word64 -> [Word8] -> Double 
random a b cs = (subtract 1) . (/(2**63)) . read . drop 8 . show $ sipHash (SipKey a b) (pack cs) 

पढ़ने और ड्रॉप 8 और दिखाने के एक newtype जो ऐसा नहीं करता ड्रॉप करने उद्देश्य पूरा (या जब मैं इस से लागू नहीं किया था) किसी भी कास्टिंग का समर्थन

+०१२३५१६४१०६१

अब आप एक श्रेणी में एक इंट चाहते हैं। पूर्णांक हालांकि आसान है:

random :: Word64 -> Word64 -> [Word8] -> (Integer, Integer) -> Integer 
random a b cs (low,high) = let 
    span = high-low 
    rand = read . drop 8 . show $ sipHash (SipKey a b) (pack cs) 
    in (rand `mod` span) + low 
निश्चित रूप से

, आप अभी भी हर बार एक ही तर्क के लिए एक ही नंबर मिल जाएगा, तो आप अलग-अलग करने के लिए उन्हें यानी आप अभी भी बहुत बहस के आसपास पारित, बस नहीं लौटे मूल्यों की आवश्यकता होगी । कि क्या और अधिक सुविधाजनक की तुलना में एक इकाई निर्भर करता है (मेरी इस प्रयोजन के लिए यह किया गया था)

यह कैसे मुझे यकीन है कि तर्क (विशेष रूप से [Word8] तर्क) हमेशा अलग हो गयी है:

foo bytes = doSomethingRandom bytes 
bar bytes = map (\i -> foo (i:bytes)) [1..n] 
baz bytes = doSomething (foo (0:bytes)) (bar (1:bytes))