3

我正在尝试学习haskell State monad。所以我写了一个函数来使用 State monad 生成一个随机数列表。

这是第一个版本。

rnds :: Int -> [Int]
rnds n = evalState (help (mkStdGen 007)) []
  where help prng = do s <- get
            let (a, nprng) = randomR (1,6) prng                                 
            put (a:s)
            if length s == n then (return s)
                             else (help nprng)

这是第二个版本。

rnds1 :: Int -> [Int]
rnds1 n = evalState (help (mkStdGen 007)) []
  where help prng = do s <- get
            let (a, nprng) = randomR (1,6) prng                                 
            put (a:s)
            ns <- get
            if length ns == n then (return ns)
                              else (help nprng)

对于相同的参数,它们都给出相同的输出。但是在第一个版本中,要检查列表的长度(顺便说一下,这是状态),我引用的是 list s。不过s是在我做之前得到的put (a:s)。所以当我检查长度时,我假设它会在我做之前给出's'的长度put (a:s)。但似乎并非如此,因为如果两个版本的参数相同,则第一个版本的输出与第二个版本相同。

第二个版本至少对我来说更容易理解。在检查列表的长度之前ns,我首先要做ns <- get的是获取新的更新状态。

有人可以告诉我发生了什么吗?我觉得我严重误解了 Haskell 的工作方式或 State monad 本身的一些东西。

谢谢并恭祝安康。

4

2 回答 2

5

rnds,

put (a:s)
if length s == n then (return s)

您返回从 获得的列表get,而不是您put进入状态的列表,因此您生成的伪随机数比 in 多一个rnds1(然后您忽略),但返回相同的列表。

于 2013-03-04T16:49:56.557 回答
4

正如丹尼尔所指出的,我认为这只是由于您使用的算法而造成的巧合。如果您使用更简单的程序,则在从隐藏状态中提取值后,更容易看到值不会“神奇地”发生突变:

module Main where
import Control.Monad.State

test = evalState comp 1
  where
    comp = do
     x <- get
     put 2
     y <- get
     return (x,y)

main = do
   print test

这个程序打印出 (1,2),表明一旦你得到x明确的“旧”值,即使你做了一个“放置”。

于 2013-03-04T16:54:51.600 回答