3

HaskellStateモナドを学ぼうとしています。そこで、Stateモナドを使用して乱数のリストを生成する関数を作成しました。

これが最初のバージョンです。

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)

これが2番目のバージョンです。

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)。したがって、長さを確認するときは、実行する前に「s」の長さになると想定しましたput (a:s)。ただし、両方に同じパラメーターが指定されている場合、最初のバージョンの出力は2番目のバージョンと同じであるため、そうではないようです。

2番目のバージョンは、少なくとも私にとっては理解しやすいものです。リストの長さを確認する前に、nsまずns <- get新しい更新された状態を取得します。

誰かが何が起こっているのか教えてもらえますか?Haskellの仕組みや州のモナド自体について何かをひどく誤解しているような気がします。

よろしくお願いします。

4

2 に答える 2

5

rnds

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

から取得したリストを返しgetますが、状態にしたリストではないため、 (無視する)putよりも多くの疑似乱数を生成しますが、同じリストを返します。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、「put」を実行した後でも、取得すると明らかに「old」値になることを示します。

于 2013-03-04T16:54:51.600 に答える