Ada*_*hus 0 random monads haskell
我需要在Haskell中创建随机数据。我希望我的代码是:a)从种子可复制b)生成器的线程是隐式的
我大致了解Monad以及随机发生器的工作方式。我的方法是通过代码对生成器进行线程处理,以便可以重现随机数,但希望将生成器的线程隐藏在Monad中。我认为State Monad是个好方法。
这是一些简单的代码:
type Gen a = State StdGen a
roll :: Gen Int
roll = state $ randomR (1, 6)
roll2 :: Gen Int
roll2 = (+) <$> roll <*> roll
test :: Int -> IO ()
test seed = do
let gen = mkStdGen seed
print (evalState roll gen)
print (evalState roll gen)
print (evalState roll2 gen)
print (evalState roll2 gen)
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用State以便将生成器的线程推入State Monad中,但是roll的结果相同,而roll2的结果相同。我可以看到这是因为我多次将gen传递给函数,因此当然会产生相同的输出。因此,我认为我需要从每个函数中获取一个新的生成器。但是,我又回到了必须通过代码使生成器线程化的问题,而这正是我试图通过使用State来避免的代码。我觉得我想念一个把戏!
我也探索了MonadRandom,这确实使线程脱离了我的代码,但是我看不到如何使这种方法可重现。
我已经狩猎了很多,尝试了很多事情,但似乎总是能够隐藏生成器,或者使代码可重现,但不能同时重现。
我热衷于使用比IO更具体的Monad。
我还将构建一系列更复杂的函数,这些函数将生成数字的随机列表,因此我需要一种简单的方法来使这些随机函数相互依赖。我用MonadRandom做到了这一点,但是我再也看不到它是如何可再现的。
任何帮助表示赞赏。
If you needn't interleave IO
with randomness, as here, then the answer is just to lump your State
actions together into one with the Monad
operations (they're the thing passing the state around for you!).
test :: Int -> IO ()
test seed = do
print a
print b
print c
print d
where
(a,b,c,d) = flip evalState (mkStdGen seed) $ do
a <- roll
b <- roll
c <- roll2
d <- roll2
return (a,b,c,d)
Run Code Online (Sandbox Code Playgroud)
If you will need to interleave IO
and randomness, then you will want to look into StateT StdGen IO
as your monad instead of using State StdGen
and IO
separately. That might look like this, say:
roll :: MonadState StdGen m => m Int
roll = state (randomR (1,6))
roll2 :: MonadState StdGen m => m Int
roll2 = (+) <$> roll <*> roll
test :: (MonadState StdGen m, MonadIO m) => m ()
test = do
roll >>= liftIO . print
roll >>= liftIO . print
roll2 >>= liftIO . print
roll2 >>= liftIO . print
Run Code Online (Sandbox Code Playgroud)
(You could then use e.g. evalStateT test (mkStdGen seed)
to turn this back into an IO ()
action, or embed it into a larger computation if there were further random things you needed to generate and do IO
about.)
MonadRandom
所做的只是打包StateT StdGen
,使您仍然可以使用非种子状态,因此,我鼓励您重新考虑使用它。evalRand
和evalRandT
来自Control.Monad.Random.Lazy
(或.Strict
)shouldy给你重复你需要; 如果他们不这样做,则您应该打开一个新问题,其中包含您尝试过的内容以及如何出错的详细信息。