这是一个非常简单的线性全等伪随机数发生器。当它播种它时,它工作正常,但我想做它,以便它与每个产生的数字自我种子。问题是我不知道在Haskell中如何做到这一点,其中变量的概念不存在。我可以递归地提供生成的数字,但之后我的结果将是整数列表而不是单个数字。
linCongGen :: Int -> Int
linCongGen seed = ((2*seed) + 3) `mod` 100
答案 0 :(得分:1)
我会更有意义地总结这些意见。与您观察到的一样,最简单的解决方案是生成元素序列的无限列表。然后,每次想要获得一个新号码时,都要弹出该列表的头部。
linCongGen :: Integral a => a -> [a]
linCongGen = iterate $ \x -> ((2*x) + 3) `mod` 100
那就是说,这是一个解决方案(我不同意),但它做了我认为你想要的。对于可变状态,我们通常使用IORef
,它有点像引用或指针。这是代码。请稍后阅读免责声明。
import Data.IORef
import System.IO.Unsafe
seed :: IORef Int
seed = unsafePerformIO $ newIORef 71
linCongGen :: IO Int
linCongGen = do previous <- readIORef seed
modifyIORef' seed $ \x -> ((2*x) + 3) `mod` 100
return previous
以下是打印出生成的前100个数字的示例用法:main = replicateM_ 100 $ getRandom >>= print
(您还需要为Control.Monad
导入replicateM_
。
这是一种描述here的hacky方法。正如链接所说:“可能需要全球可变状态是设计糟糕的症状。”该链接还具有更智能的解决方法的良好描述。制作IORef
是一项固有的IO
操作,我们真的不应该在其上使用unsafePerformIO
。如果你发现自己以这种方式与Haskell作战,那是因为Haskell的设计是为了在你不应该做的事情上妨碍你。
那就是说,我很高兴知道这种方法也是用System.Random(标准随机数模块)来定义初始种子(check out the source)的方法。