如何在Haskell中生成不同的随机值? [英] How can I generate different random values in Haskell?

查看:57
本文介绍了如何在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".

推荐答案

您的代码有两个问题:

  1. 您正在调用unsafePerformIO,但明显违反了该功能的约定.您有责任证明您提供给unsafePerformIO的东西实际上是纯净的,并且编译器在其权限范围内,就像是那样,而在这里绝对不是.
  2. 使用后,您没有仔细跟踪更新后的随机数生成器的状态.实际上,使用randomRs不可能正确执行此操作.如果使用randomRs,则近似为一阶近似值,必须是程序所需的 last 随机性.
  1. You are calling unsafePerformIO, but explicitly violating the contract of that function. It is on you to prove that the thing you provide to unsafePerformIO is actually pure, and the compiler is within its rights to act as if that's the case, and here it is definitely not.
  2. 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 use randomRs, 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,因此没有证据负担. randomRIOrandomRIO在隐藏的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆