如何在Haskell中生成不同的随机值? [英] How can I generate different random values in Haskell?
问题描述
假设我有一个这样的列表:
Suppose that I have a list like this:
let list = ["random", "foo", "random", "bar", "random", "boo"]
我想遍历列表并将所有随机"元素映射到不同的随机字符串:
I want to iterate over a list and map all "random" elements to different random strings:
let newList = fmap randomize list
print newList
-- ["dasidias", "foo", "gasekir", "bar", "nabblip", "boo"]
我的随机函数如下:
randomize :: String -> String
randomize str =
case str of
"random" -> randStr
_ -> str
where
randStr = take 10 $ randomRs ('a','z') $ unsafePerformIO newStdGen
但是对于每个随机"元素,我都会得到相同的随机字符串:
But I get the same random string for every "random" element:
["abshasb", "foo", "abshasb", "bar", "abshasb", "boo"]
我不知道为什么会这样,以及如何为每次出现的随机"获得不同的随机值.
I can't figure out why is this happening and how to get a different random value for each occurrence of "random".
推荐答案
您的代码有两个问题:
- 您正在调用
unsafePerformIO
,但明显违反了该功能的约定.您有责任证明您提供给unsafePerformIO
的东西实际上是纯净的,并且编译器在其权限范围内,就像是那样,而在这里绝对不是. - 使用后,您没有仔细跟踪更新后的随机数生成器的状态.实际上,使用
randomRs
不可能正确执行此操作.如果使用randomRs
,则近似为一阶近似值,必须是程序所需的 last 随机性.
- You are calling
unsafePerformIO
, but explicitly violating the contract of that function. It is on you to prove that the thing you provide tounsafePerformIO
is actually pure, and the compiler is within its rights to act as if that's the case, and here it is definitely not. - You are not carefully tracking the updated random number generator state after using it. Indeed, it is not possible to do this correctly with
randomRs
; if you userandomRs
, then to a first approximation, that must be the last randomness your program needs.
这两个方法最简单的解决方法是承认您确实在做IO
.所以:
The simplest fix to both of these is to admit that you really, truly are doing IO
. So:
import Control.Monad
import System.Random
randomize :: String -> IO String
randomize "random" = replicateM 10 (randomRIO ('a', 'z'))
randomize other = pure other
在ghci中试用:
> traverse randomize ["random", "foo", "random", "bar", "random", "boo"]
["xytuowzanb","foo","lzhasynexf","bar","dceuvoxkyh","boo"]
没有呼叫unsafePerformIO
,因此没有证据负担. randomRIO
和randomRIO
在隐藏的IORef
中为您跟踪更新的生成器状态,因此您可以在每次调用时正确地继续前进.
There is no call to unsafePerformIO
, and so no proof burden to shirk; and randomRIO
tracks the updated generator state for you in a hidden IORef
, and so you correctly continue advancing it on each call.
这篇关于如何在Haskell中生成不同的随机值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!