【发布时间】:2018-01-07 21:49:19
【问题描述】:
这是一个非常新手的问题,虽然我可以找到部分答案,但我仍然很难让整个事情发挥作用。我在一个模块中有一组函数,可以处理我设计的特定数据类型。有时我需要创建一个随机值列表。我们可以将我的类型视为多项式,以它们的系数列表的形式给出。所以我应该只需要调用一个randomPoly 函数(比如说)在每次调用它时生成新列表。为简单起见,所有列表都可以是相同的长度(比如 4)和相同大小的元素 - 比如在 0 到 9 之间。
所以我想要的是能够做这样的事情(在 ghci 中):
>>> setRandomSeed 42
>>> randomPoly
[6,5,0,4]
>>> randomPoly
[9,6,3,5]
>>> randomPoly
[7,3,9,2]
我当然可以在每次需要新列表时通过简单地将新种子传递给生成器来获得不同的随机列表:
>>> randomPoly st = map (`mod` 10) $ take 4 $ randoms (mkStdGen st) :: [Integer]
但我不想这样做:我想设置一次初始种子,然后让 State 负责管理生成器的当前值。
在这个阶段,我对 monad、State 和所有其他东西的本质不太感兴趣 - 我正在寻找尽可能接近“现成”的解决方案。我只是想要一些我可以使用的东西。大多数示例似乎都非常热衷于教授所有有关 State monad 的工作原理 - 这是一个非常光荣的概念 - 但现在我想要的只是一些快速简单的方法,以便在我需要它们时创建随机列表。
例如,这是一个愚蠢的函数,它创建随机列表直到所有值的总和为偶数:
mkEvenPoly :: Int -> [Integer]
mkEvenPoly st
| even $ sum p = p
| otherwise = mkEvenPoly $ s+1
where
p = map (`mod` 10) $ take 4 $ randoms (mkStdGen st) :: [Integer]
请注意,每次我需要将新的生成值传递给mkStdGen。我可以用 State monad 做这种事情吗 - 存储生成器的当前值(由 mkStdGen 返回),然后将其用于下一次随机调用?
【问题讨论】:
-
您通过传递
StdGen作为状态来使用random库(例如,将其传递给random,然后继续从调用返回的StdGen进行下一个伪随机值等)。所以你应该给mkStdGen打一次电话。我首先将mkEvenPoly重写为StdGen -> [Integer]类型,暂时忽略Statemonad -
关于如何使用
State来抽象StdGen的“有状态”传递,我认为你应该从网上的许多小例子之一开始,逐步适应你的功能,或者只是接受您可能需要花一些时间来学习它们。 -
MonadRandom提供了一个相当不错的界面,我认为可能还有其他类似的。 -
谢谢各位。是的,当然——我正在花时间学习这个——但这需要相当多的时间!这也有点令人沮丧:每次我认为我有一个概念被舔过时,都会有一些小细节需要在挖掘细节方面进行另一次投资。呃,好吧。正如他们所说,没有王道......
标签: haskell random state-monad