2010-08-06 11 views
5

मैं हास्केल के लिए नया हूं और मुझे आश्चर्य है कि कैसे/अगर मैं यह कोड अधिक कुशल और साफ कर सकता हूं। यह अनावश्यक रूप से लंबे और अस्पष्ट लगता है।वितरण उत्पन्न करने के लिए कोड में सुधार

मेरी लिपि 10 सिक्का फ्लिप के 10 औसत की एक सूची उत्पन्न करती है।

import Data.List 
import System.Random 

type Rand a = StdGen -> Maybe (a,StdGen) 

output = do 
    gen <- newStdGen 
    return $ distBernoulli 10 10 gen 

distBernoulli :: Int -> Int -> StdGen -> [Double] 
distBernoulli m n gen = [fromIntegral (sum x)/fromIntegral (length x) | x <- lst] 
    where lst = splitList (randomList (n*m) gen) n 

splitList :: [Int] -> Int -> [[Int]] 
splitList [] n = [] 
splitList lst n = take n lst : splitList (drop n lst) n 

randomList :: Int -> StdGen -> [Int] 
randomList n = take n . unfoldr trialBernoulli 

trialBernoulli :: Rand Int 
trialBernoulli gen = Just ((2*x)-1,y) 
       where (x,y) = randomR (0,1) gen 

किसी भी मदद की सराहना की जाएगी, धन्यवाद।

उत्तर

3

मैं इस समस्या से थोड़ा अलग तरीके से निपटूंगा।

flips :: Double -> StdGen -> [Bool] 
flips p = map (< p) . randoms 

तब मैं distBernoulli लिखते हैं इस प्रकार है::

distBernoulli :: Int -> Int -> StdGen -> [Double] 
distBernoulli m n = take m . map avg . splitEvery n . map val . flips 0.5 
    where 
    val True = 1 
    val False = -1 
    avg = (/ fromIntegral n) . sum 

मुझे लगता है कि सबसे पहले मैं एक समारोह है कि मुझे सफलता संभावना p के साथ एक Bernoulli वितरण से flips की एक अनंत नमूना देना होगा निर्धारित करेंगे इस से मेल खाता है distBernoulli की अपनी परिभाषा:

*Main> distBernoulli 10 10 $ mkStdGen 0 
[-0.2,0.4,0.4,0.0,0.0,0.2,0.0,0.6,0.2,0.0] 

(ध्यान दें कि मैं हा से splitEvery उपयोग कर रहा हूँ ndy split पैकेज, तो आपको पैकेज को स्थापित करना होगा और import Data.List.Split (splitEvery) को अपने आयात में जोड़ना होगा।)

यह दृष्टिकोण थोड़ा अधिक सामान्य है, और मुझे लगता है कि थोड़ा साफ है, लेकिन वास्तव में मुख्य अंतर यह है कि मैं हूं randoms और splitEvery का उपयोग कर।

0

मुझे यकीन है कि मैं अपने कोड या अपने प्रश्न समझ में नहीं हूँ ...

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

कुछ की तरह:

makeList n फूल = n/= 0 तो makeList (n-1) randomR (0,1) यदि: फूल बाकी फूल

और फिर इसे एक लागू मानचित्र और फ़ोल्डर या फ़ोल्डर में।

+0

खेद का स्वागत करते हैं, मैं बुरी तरह से समझाने की थी। मैं मूल रूप से मानक सामान्य वितरण बनाने के लिए डेटा बनाने की कोशिश कर रहा हूं। वस्तुतः एक सिक्का (परिणाम 1 या -1 के साथ) 10 बार, और परिणाम की औसत ले कर, हम कहते हैं -0.2। इस प्रक्रिया को करके 1000 बार कहते हैं, हम परिणाम और उनकी आवृत्ति को साजिश कर सकते हैं और सामान्य वितरण प्राप्त कर सकते हैं। मैं युगल की एक सूची बनाने की कोशिश कर रहा हूं कि मैं इस वितरण को आकर्षित करने के लिए साजिश कर सकता हूं। स्पष्टीकरण के लिए – Ash

+0

, इस स्क्रिप्ट का परिणाम [0.2,0.0,0.0, -0.4,0.6,0.0, -0.2,0.2,0.4,0.0] हो सकता है – Ash

2

संपादित करें: मैंने इसे बहुत तेज़ पोस्ट किया और व्यवहार से मेल नहीं खाया, यह अब अच्छा होना चाहिए।

import Control.Monad.Random 
import Control.Monad (liftM, replicateM) 

ज्ञान: आप randoms को पसंद करते हैं तो MonadRandom का उपयोग करें - यह पत्थर।

स्टाइल: केवल आपके द्वारा उपयोग किए जाने वाले प्रतीकों को आयात करने में पठनीयता और कभी-कभी बनाए रखने में मदद मिलती है।

output :: IO [Double] 
output = liftM (map dist) getLists 

नोट: मैं उत्पादन एक स्पष्ट प्रकार दी है, लेकिन पता है कि यह नहीं करता आईओ किया जाना है।

शैली:

1) इसके आमतौर पर शुद्ध कार्यों से अपने आईओ अलग करने के लिए अच्छा है। यहां मैंने वितरण की गणना से यादृच्छिक सूचियों को प्राप्त करने में विभाजित किया है। आपके मामले में यह शुद्ध था लेकिन आप वितरण कार्य के साथ जेनरेटर के माध्यम से "यादृच्छिक" सूचियां प्राप्त कर रहे थे; मैं उन हिस्सों को विभाजित कर दूंगा।

2) Do notation considered harmful पढ़ें।

output = do 
    gen <- new 
    return $ dist gen 

के बजाय >>= का उपयोग कर आप कर सकते हैं पर विचार करें:

output = new >>= dist 

वाह!

dist :: [Int] -> Double 
dist lst = (fromIntegral (sum lst)/fromIntegral (length lst)) 

getLists :: MonadRandom m => Int -> Int -> m [[Int]] 
getLists m n= replicateM m (getList n) 

ज्ञान Control.Monad कुछ भी एक M में समाप्त होने में मूल की तरह लेकिन monads के लिए है। इस मामले में, replicateM परिचित होना चाहिए यदि आपने डेटा का उपयोग किया था। लिस्ट replicate फ़ंक्शन।

getList :: MonadRandom m => Int -> m [Int] 
getList m = liftM (map (subtract 1 . (*2)) . take m) (getRandomRs (0,1::Int)) 

स्टाइल: मैं अपनी ही समारोह (getList) फिर एक अलग समारोह में पुनरावृत्ति में एक उदाहरण चाहते अगर मैं समय की कुछ बहुत सारे है।

0

उपरोक्त का उपयोग करके, अब मैं इसका उपयोग कर रहा हूं।

import Data.List 
import System.Random 

type Rand a = [a] 

distBernoulli :: Int -> Int -> StdGen -> [Double] 
distBernoulli m n gen = [fromIntegral (sum x)/fromIntegral (length x) | x <- lst] 
    where lst = take m $ splitList (listBernoulli gen) n 

listBernoulli :: StdGen -> Rand Int 
listBernoulli = map (\x -> (x*2)-1) . randomRs (0,1) 

splitList :: [Int] -> Int -> [[Int]] 
splitList lst n = take n lst : splitList (drop n lst) n 

आपकी मदद के लिए धन्यवाद, और मैं किसी भी आगे की टिप्पणी :)

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