2015-08-08 32 views
5

Haskell yolculuğumun bir parçası olarak, bir raytracer uyguluyor ve kodun çeşitli yerlerinde rastgele sayı dizileri çizebilmem gerekiyor. Tipik olarak her piksel için 64 örnek alıp pikselleri paralel olarak hesaplamak istiyorum.Rasgele sayı dizisi un Haskell ve State Monad, ne yapıyorum yanlış?

Bunu başarmak için eyalet monadına bakıyordum ve bu cevabı Sampling sequences of random numbers in Haskell tarafından yönlendirildim ancak yazdığım kod sonlanmıyor ve bellek tüketimi patlıyor. İşte

kod soyutlanmış bir parçasıdır: Ben rasgele sayı yeni listeler almak için kod sampleUniform birkaç kez çağırmak edebilmek için attırmak ama runhaskell test.hs yaparsak, bu lis [ ilk karakteri verir ve sonra görünüşte sonsuz bir döngüde sıkışmış.

module Main (main 
      , computeArray) where 

import Control.Monad 
import Control.Monad.State (State, evalState, get, put) 
import System.Random (StdGen, mkStdGen, random) 
import Control.Applicative ((<$>)) 

type Rnd a = State StdGen a 

runRandom :: Rnd a -> Int -> a 
runRandom action seed = evalState action $ mkStdGen seed 

rand :: Rnd Double 
rand = do 
    gen <- get 
    let (r, gen') = random gen 
    put gen' 
    return r 

{- Uniform distributions -} 
uniform01 :: Rnd [Double] 
uniform01 = mapM (\_ -> rand) $ repeat() 

{- Get n samples uniformly distributed between 0 and 1 -} 
sampleUniform :: Int -> Rnd [Double] 
sampleUniform n = liftM (take n) uniform01 

computeArray :: Rnd [Bool] 
computeArray = do 
    samples1 <- sampleUniform 10 
    samples2 <- sampleUniform 10 
    let dat = zip samples1 samples2 
    return $ uncurry (<) <$> dat 

main :: IO() 
main = do 
    let seed = 48 
    let res = runRandom computeArray seed 
    putStrLn $ show res 
+0

Ayrıca bkz [Haskell dizisi fonksiyonu tembel olamaz ya da neden özyinelemeli monadic fonksiyonlar tembel olamaz Neden] (http://stackoverflow.com/q ile/31892418/1333025) .. –

cevap

5

uniform01 konu o tembelce onun sonucu üretir rağmen, kullanılacak sonunda nihai devlet alınırken hiçbir umut demektir hesaplamaların bir sonsuz numarası, aracılığıyla devlet sonraki örnekleme. liftM (take n) sadece son değeri etkiler, hesaplamak için kullanılan durum etkilerini değil. Bu nedenle, yazılı olarak, yalnızca bir kez uniform01/sampleUniform'u kullanabilirsiniz. Bunun yerine, kullandığınız gibi, yalnızca rand eylemlerini kullanarak durumu işleyebilirsiniz.

sampleUniform n = mapM (\_ -> rand) $ replicate n() 

veya daha basit

sampleUniform n = sequence $ replicate n rand 
+1

Hatta 'replicateM n rand' – chi

+0

Harika, açıklama ve doğru çözüm için teşekkürler! – overlii

+0

Şimdi antialiazing yapabilirim :) Sıradaki soru, bu Devlet Monadını paralel olarak kullanabilir miyim? Yoksa iş parçacığı başına devlete sahip olmak daha mı iyi olurdu? Başka bir hafta sonu olabilir :) – overlii