这两个非常相似的haskell状态计算之间的区别是什么

时间:2013-03-04 16:40:41

标签: haskell state

我正在努力学习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)

对于相同的参数,它们都给出相同的输出。但是在第一个版本中,为了检查列表的长度(顺便说一下是状态),我引用了列表s。但是在我s之前获得了put (a:s)。因此,当我检查长度时,我认为它会在我put (a:s)之前给出's'的长度。但它似乎并非如此,因为如果给出相同的参数,第一个版本的输出与第二个版本的输出相同。

第二版对我来说更容易理解。在检查列表ns的长度之前,我首先执行ns <- get以获取新的更新状态。

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

谢谢和问候。

2 个答案:

答案 0 :(得分:5)

rnds

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

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

答案 1 :(得分: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明显有“旧”值。