haskell中的线性全等发生器

时间:2015-06-16 22:36:49

标签: haskell

这是一个非常简单的线性全等伪随机数发生器。当它播种它时,它工作正常,但我想做它,以便它与每个产生的数字自我种子。问题是我不知道在Haskell中如何做到这一点,其中变量的概念不存在。我可以递归地提供生成的数字,但之后我的结果将是整数列表而不是单个数字。

linCongGen :: Int -> Int
linCongGen seed = ((2*seed) + 3) `mod` 100

1 个答案:

答案 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)的方法。