我正在努力学习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本身的一些事情。
谢谢和问候。
答案 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
明显有“旧”值。