【问题标题】:Random numbers and getStdGen随机数和 getStdGen
【发布时间】:2014-12-28 08:32:16
【问题描述】:

来自我们拥有的 Haskell wikibook:

import Control.Monad
import Control.Monad.Trans.State
import System.Random

type GeneratorState = State StdGen

rollDie :: GeneratorState Int
rollDie = do
  generator <- get
  let (value, newGenerator) = randomR (1,6) generator
  put newGenerator
  return value

如果我们执行:

evalState rollDie (mkStdGen 0)

然后我们得到一个 Int 的返回类型。

我明白这一点,但我想知道是否可以将由函数 getStdGen 访问的系统生成器的使用连接到这个逻辑中。 getStdGen 函数在 IO monad 中运行,我的问题是(这肯定是 Haskell 最常被问到的问题)如何让生成器脱离 IO 上下文以在上面的非 IO monad 代码中使用?

为新手问题道歉。我知道不应该使用 unsafePerformIO,否则会感到困惑。

【问题讨论】:

  • 您想要的可能是MonadRandom 类(在Control.Monad.Random 中)。如果你写了一个MonadRandom m =&gt; m Int类型的函数,那么你可以用IO Int来实例化它,这将使用getStdGen,或者Rand Int(Rand是一个特殊的monad,用于生成随机数,本质上和State StdGen一样) ,您可以照常使用。然而,最简单的解决方案是evalState rollDie `fmap` getStdGen,它只是将函数evalState rollDie 应用于getStdGen 创建的StdGen。
  • 这个关于随机数的问题完全是关于 IO 以及如何使用绑定?

标签: haskell monads


【解决方案1】:

问题的核心是不可能凭空产生随机数。您可以使用一些输入为生成器播种(这就是您使用 mkStdGen 0 所做的),或者您可以使用 getStdGen 获取系统之一。

mkStdGen 0 的问题在于它是一个常数,因此您的随机数流也将通过成为常数来非常清楚地显示其伪随机性。

getStdGen 的问题在于它在 IO monad 中。

您无法将生成器从 IO 中取出以用于纯计算,这就是使 IO 成为 monad 的全部意义所在。但是在 IO 中,你可以使用普通的 do-notation 来绑定它:

main = do
  gen <- getStrGen
  print $ evalState rollDie gen

当然,它只会产生一次独特的结果。

我衷心同意the comment recommending MonadRandom。自从我发现它以来,我一直在使用它进行基于随机的计算,并且没有回头。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-10
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    相关资源
    最近更新 更多