使用foldM生成随机数列表

时间:2012-01-14 22:10:54

标签: haskell random monads

我想生成随机数列表,其中每个随机数的范围由提供列表的元素确定。我以为我有一些有意义的东西,但我得到的错误我不明白:(

这就是我所拥有的:

useRNG nums min = do
    generator <- get
    let (val, generator') = randomR (min, 51) generator
    put generator'
    return $ val : nums

foldM useRNG [] [0 .. 50]

任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:4)

问题是useRNG可以生成各种数字(Random的任何实例),并且可以在各种monad中工作(任何状态monad,其状态是{{1}的实例从其推断的类型签名可以看出:

RandomGen

...但是当你使用它时,你没有指定你真正想要的具体类型。

如果您使用类型签名消除歧义:

GHCi> :t useRNG
useRNG
  :: (MonadState s m, RandomGen s, Random a, Num a) =>
     [a] -> a -> m [a]

然后它工作正常。您还可以通过在test :: State StdGen [Int] test = foldM useRNG [] [0 .. 50] 上添加类型签名来实现此目的:

useRNG

现在,您可能会想:如果useRNG :: [Int] -> Int -> State StdGen [Int] 适用于所有这些类型,为什么useRNG也不能呢?答案是monomorphism restriction,它是相当神秘的,并且很多Haskell用户都不喜欢。你可以通过放

来避免它
test

位于文件顶部,或者为{-# LANGUAGE NoMonomorphismRestriction #-} 提供显式类型签名:

test

您可以使用GHCi找到正确的类型签名:

test :: (RandomGen g, Random a, Num a, Enum a, MonadState g m) => m [a]

(我在用GHCi检查之前写了显式类型签名,这就是为什么我的略有不同。)

但是,这种类型的签名对于实际应用来说有点太多多态 - 你基本上会在实际使用结果之前放下歧义 - 所以我建议更具体地指定它这个例子。例如,你可以在随机数的类型上保持GHCi> :t foldM useRNG [] [0 .. 50] foldM useRNG [] [0 .. 50] :: (MonadState s m, RandomGen s, Random b, Num b, Enum b) => m [b] 泛型,而不需要状态monad和生成器类型的不必要的多态性:

test

您可能还想考虑使用MonadRandom,它将所有标准随机数生成工具包装在基于状态monad的接口中,因此您不必:)