使用foldM生成随机数列表

发布于 2024-12-27 02:07:03 字数 304 浏览 2 评论 0原文

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

这就是我所拥有的:

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

foldM useRNG [] [0 .. 50]

任何人都可以帮助我吗?

I want to generate a list of random numbers, where the range of each random number is determined by elements of a provided list. I thought I had something that made sense, but I get errors I don't understand :(

Here's what I have:

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

foldM useRNG [] [0 .. 50]

Can anyone help me out?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡淡绿茶香 2025-01-03 02:07:03

问题是 useRNG 可以生成各种类型的数字(Random 的任何实例),并且可以在各种类型的 monad 中工作(状态为 Random 实例的任何状态 monad) code>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 可以很好地处理所有这些类型,为什么 不能也测试一下吗?答案是单态限制,这是相当晦涩难懂的- 受到许多 Haskell 用户的喜欢。您可以通过将其放在

{-# LANGUAGE NoMonomorphismRestriction #-}

文件顶部或给 test 一个显式类型签名来避免这种情况:

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]

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

但是,这种类型签名对于实际用途来说有点太多多态性 - 你基本上会推迟歧义,直到你实际使用结果 - 所以我建议更具体地指定它在这种情况下。例如,您可以保持随机数类型的 test 通用性,而无需对状态单子和生成器类型进行不必要的多态性:

test :: (Random a, Num a, Enum a) => State StdGen [a]

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

The problem is that useRNG can generate all kinds of numbers (any instance of Random), and work in all kinds of monads (any state monad whose state is an instance of RandomGen), as can be seen from its inferred type signature:

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

...but when you use it, you haven't specified which concrete types you actually want.

If you disambiguate with a type signature:

test :: State StdGen [Int]
test = foldM useRNG [] [0 .. 50]

then it works fine. You could also accomplish this by putting a type signature on useRNG:

useRNG :: [Int] -> Int -> State StdGen [Int]

Now, you might be thinking: if useRNG works fine with all these types, why can't test too? The answer is the monomorphism restriction, which is fairly arcane and not well-liked by many Haskell users. You can avoid it by either putting

{-# LANGUAGE NoMonomorphismRestriction #-}

at the top of your file, or giving test an explicit type signature:

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

You can find out the correct type signature with GHCi:

GHCi> :t foldM useRNG [] [0 .. 50]
foldM useRNG [] [0 .. 50]
  :: (MonadState s m, RandomGen s, Random b, Num b, Enum b) => m [b]

(I wrote the explicit type signature before checking with GHCi, which is why mine is slightly different.)

However, this type signature is a little too polymorphic for practical uses — you'll basically be putting the ambiguity off until you actually use the result — so I'd suggest specifying it more concretely in this instance. You could, for instance, keep test generic over the type of random number without the needless polymorphism over the state monad and generator type:

test :: (Random a, Num a, Enum a) => State StdGen [a]

You might also want to consider using MonadRandom, which wraps all the standard random number generation facilities in a state monad-based interface so you don't have to :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文