2010-05-28 10 views
17

मैं एक Haskell समारोह है कि किसी भी सूची में से एक यादृच्छिक संख्या बाहर ले सकते हैं बनाना चाहते हैं। मेरे प्रकार हस्ताक्षर है:शुद्ध फ़ंक्शन में यादृच्छिक सूची तत्व कैसे चुनें?

randomPick :: [a] -> a 

मुझे क्या करना चाहिए?

+1

क्यों आप ऐसा करना चाहते हैं:

यहाँ कुछ उपयोगी कोड मैंने लिखा है और कभी कभी का उपयोग है? यदि आप हमें बताते हैं, तो शायद हम आपको (सच्चे) "सच्चाई" से अधिक उपयोगी उत्तर दे सकते हैं। –

+15

यहां आप जाते हैं: 'randomPick = (!! 7)' (मैंने यादृच्छिक रूप से नंबर 7 को पूरी तरह से चुना है) – yairchu

+2

@Yairchu: अच्छा विकल्प, क्योंकि [7 में समाप्त होने वाली संख्या वास्तव में बहुत यादृच्छिक हैं] (http://scienceblogs.com /cognitivedaily/2007/02/is_17_the_most_random_number.php)। एक संदर्भित पारदर्शी आरएनजी के लिए [यह संभव कार्यान्वयन] (http://www.random.org/analysis/dilbert.jpg) भी देखें। –

उत्तर

22

आप क्या वर्णन किया है शुद्ध कार्यात्मक कोड में नहीं किया जा सकता।

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

रूप @camccann's answer में विस्तार से बताया जब तक आप एक अतिरिक्त मूल्य के आसपास गुजरती हैं। तकनीकी रूप से, इसे आपकी आवश्यकताओं के आधार पर आरएनजी के रूप में भी उन्नत नहीं होना चाहिए। आप एक पूर्णांक के चारों ओर गुजर सकते हैं, और इसे 10 से गुणा कर सकते हैं और 3 (या जो भी हो) घटा सकते हैं, फिर अपनी अनुक्रमणिका ढूंढने के लिए इसका मॉड्यूल लें। फिर आपका कार्य शुद्ध रहता है, लेकिन आप सीधे यादृच्छिकता को नियंत्रित करते हैं।

एक अन्य विकल्प RandomRIO उपयोग करने के लिए एक सीमा है, जिसे आप फिर सूची में से एक सूची का चयन करने के लिए उपयोग कर सकते में एक संख्या उत्पन्न करने के लिए है। आपको आईओ मोनड में प्रवेश करने की आवश्यकता होगी। हास्केल में एक "शुद्ध" समारोह की परिभाषा की

+0

क्या मैं एक अन्य कार्य कर सकता हूं जैसे: यादृच्छिक विकल्प :: [ए] -> एक randomChoices XS = randomIO (makeIO XS) makeIO :: [एक] -> आईओ [एक] makeIO = त्रुटि "कोई नहीं" randomIO :: आईओ [एक] -> एक randomIO = त्रुटि " कोई भी " यदि ऐसा है तो कैसे? – user345662

+1

नहीं, यह संभव नहीं है; जबकि 'मेकियो :: [ए] -> आईओ [ए]' सिर्फ 'रिटर्न' है, टाइप 'आईओ ए -> ए' के ​​साथ कोई फ़ंक्शन नहीं है- आईओ मोनैड को दर्ज करने के बाद कोई रास्ता नहीं है। ऐसा इसलिए है क्योंकि, जैसा कि मार्क ने कहा था, हास्केल शुद्ध है: आप चर के मानों को नहीं बदल सकते हैं, और इसलिए हर बार जब कोई फ़ंक्शन इनपुट दिया जाता है, तो उसे हमेशा एक ही आउटपुट वापस करना होगा। चूंकि 'आईओ' उन कार्रवाइयों का प्रतिनिधित्व करने का एक शुद्ध तरीका है, जब लिया जाता है, हो सकता है (वे प्रतीत होते हैं) चीजों को म्यूट कर सकते हैं, यह अनियंत्रित होना चाहिए, और इसकी परिभाषा छिपी हुई है और 'आईओ' से एक समारोह की कमी से लागू है ए -> ए'। –

25

हिस्सा है कि है, यह मूल्यांकन करने का परिणाम के साथ परस्पर विनिमय है कि यह referentially transparent है। इसका तात्पर्य यह है कि इसका मूल्यांकन करने का नतीजा हर बार समान होना चाहिए। Ergo, जो काम आप चाहते हैं वह संभव नहीं है, मुझे डर है।

लें और वापसी एक कूट-यादृच्छिक संख्या जनरेटर, जैसे::

randomPick :: RNG -> [a] -> (a, RNG) 

या "बाहर की दुनिया" से अनियमितता का उपयोग करने की IO का उपयोग हास्केल में यादृच्छिक संख्या उत्पन्न करने के लिए एक समारोह दो चीजों में से एक करने की जरूरत है :

randomPick :: [a] -> IO a 

दोनों शैलियों the module System.Random द्वारा प्रदान की जाती हैं। इसके अलावा, पूर्व मामले में, PRNG के आसपास गुजर बाहर State इकाई, या शायद एक special-purpose Random monad का उपयोग कर निकाला जा सकता है।

+4

हां, मोनाड्रैंडम देखें (इस उत्तर में लिंक) - मैं यहां विशेष रूप से उल्लेख करने आया था कि अगर यह पहले से नहीं था। –

+2

आप क्विक चेक के "जनरल" मोनैड का उपयोग एक आसान तैयार बेक्ड कार्यान्वयन के रूप में भी कर सकते हैं। अन्य चीजों के अलावा इसमें पहले से ही आवश्यक क्रिया लागू है। –

5

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

rand :: (Random a, RandomGen g, MonadState g m) => a -> a -> m a 
rand lo hi = do 
    r <- get 
    let (val, r') = randomR (lo, hi) r 
    put r' 
    return val 
संबंधित मुद्दे