假设我有一个这样的列表:
let list = ["random", "foo", "random", "bar", "random", "boo"]
我想遍历一个列表并将所有“随机”元素映射到不同的随机字符串:
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
但是对于每个“随机”元素,我都会得到相同的随机字符串:
["abshasb", "foo", "abshasb", "bar", "abshasb", "boo"]
我不知道为什么会这样,以及如何为每次出现的“随机”获得不同的随机值。
您的代码有两个问题:
unsafePerformIO,但明显违反了该功能的约定。您必须证明提供给您的东西unsafePerformIO实际上是纯净的,并且编译器在其权限范围内,就像是在那样做,在这里绝对不是。randomRs; 来正确地做到这一点。如果使用randomRs,则近似为一阶近似值,它必须是程序所需的最后一个随机性。解决这两个问题的最简单方法就是承认您确实在做IO。所以:
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在hidden中为您跟踪更新的生成器状态IORef,因此您可以在每次调用时正确地继续前进。
| 归档时间: | 
 | 
| 查看次数: | 120 次 | 
| 最近记录: |