随机数序列 un Haskell 和 State Monad,我做错了什么?
Random number sequence un Haskell and State Monad, what am I doing wrong?
作为我 Haskell 旅程的一部分,我正在实现一个光线追踪器,我需要能够在代码中的多个位置绘制随机数序列。通常我希望能够为每个像素和像素并行计算 64 个样本。
我正在寻找状态 monad 来实现这一点,我被这个答案引导 Sampling sequences of random numbers in Haskell 但是我写的代码没有终止,它的内存消耗激增。
这里是代码的抽象部分:
我希望能够在代码中多次调用 sampleUniform
以获得新的随机数列表,但如果我这样做 runhaskell test.hs
,它会输出 lis [
的第一个字符,然后它陷入了一个明显的无限循环。
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
uniform01
通过 无限 次计算对您的状态进行线程化处理,这意味着尽管它会延迟生成 result,没有希望在最后检索最终的 state 以用于下一次采样。 liftM (take n)
只影响最终值,不影响用于计算它的状态效应。因此,正如所写,您只能使用 uniform01
/sampleUniform
一次。
相反,您可以仅通过您使用的 rand
个操作来线程化状态,例如与
sampleUniform n = mapM (\_ -> rand) $ replicate n ()
或更简单
sampleUniform n = sequence $ replicate n rand
作为我 Haskell 旅程的一部分,我正在实现一个光线追踪器,我需要能够在代码中的多个位置绘制随机数序列。通常我希望能够为每个像素和像素并行计算 64 个样本。
我正在寻找状态 monad 来实现这一点,我被这个答案引导 Sampling sequences of random numbers in Haskell 但是我写的代码没有终止,它的内存消耗激增。
这里是代码的抽象部分:
我希望能够在代码中多次调用 sampleUniform
以获得新的随机数列表,但如果我这样做 runhaskell test.hs
,它会输出 lis [
的第一个字符,然后它陷入了一个明显的无限循环。
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
uniform01
通过 无限 次计算对您的状态进行线程化处理,这意味着尽管它会延迟生成 result,没有希望在最后检索最终的 state 以用于下一次采样。 liftM (take n)
只影响最终值,不影响用于计算它的状态效应。因此,正如所写,您只能使用 uniform01
/sampleUniform
一次。
相反,您可以仅通过您使用的 rand
个操作来线程化状态,例如与
sampleUniform n = mapM (\_ -> rand) $ replicate n ()
或更简单
sampleUniform n = sequence $ replicate n rand