我想生成随机数列表,其中每个随机数的范围由提供列表的元素确定。我以为我有一些有意义的东西,但我得到的错误我不明白:(
这就是我所拥有的:
useRNG nums min = do
generator <- get
let (val, generator') = randomR (min, 51) generator
put generator'
return $ val : nums
foldM useRNG [] [0 .. 50]
任何人都可以帮助我吗?
答案 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的接口中,因此您不必:)