2

これはhttps://wiki.haskell.org/All_About_MonadsStateの例です。モナドを 使用StdGenして一連の乱数生成コマンドに値を通す例です。return最後のものが正しく機能することを理解していれば、値として新しいモナドを作成するだけです。xしかし、put g'実際には何をするのでしょうか? g'実際に失われないのはなぜですか?

getAny :: (Random a) => State StdGen a
getAny = do g <- get
            (x,g') <- return $ random g
            put g'
            return x
4

2 に答える 2

3

私たちの状態がファイルに保存されているとしましょう。以下はgetAny、Javascript/Python に似た言語で表現した場合の動作です。

function getAny() {
  var g = readStateFromFile("some-path")  // the get call

  var xg  = random(g)    // returns an array with two elements
  var x = xg[0]
  var newg = xg[1]

  writeStateToFile("some-path", newg)  // same as the put function call
  return x
}

ここでrandom(g)は 2 つの値を返す必要があるため、配列を返すようにしています。

この一連の呼び出しで何が起こるかを考えてみましょう。

 a = getAny()       same as:    do a <- getAny
 b = getAny()                      b <- getAny
 c = getAny()                      c <- getAny

の場合a = getAny():

  • 状態はファイルから読み取られます
  • randomそれは2つの値を返すに与えられます
  • 2 番目の値がファイルに書き込まれます
  • 最初の値が返され、変数に格納されますa

そして、次の場合b = getAny():

  • ファイルに書き込まれたばかりの状態が読み戻されます
  • random()それは価値と新しい状態を生み出すために供給されます
  • 新しい状態がファイルに書き込まれます
  • 新しい値が返され、変数に格納されますb

等...

あなたの質問に答えるために:

put g' は実際に何をしますか?

状態を新しい値で更新します。

g' が実際に失われないのはなぜですか?

newgは単なるローカル変数なので、どこかに保存しない限り値は失われます。

于 2016-06-19T16:13:30.410 に答える
1

私はあなたが混乱していると思います

(x, g') <- return $ random g

State StdGen (a, StdGen)これは確かに、その結​​果を抽出するために実行される新しいモナド アクションを作成します(a, StdGen)

コードが実際に同等であるため、混乱は正当な理由で発生します

let (x, g') = random g

モナドアクションが構築されていないため、より単純なコードになります。この変換は、モナドだけでなく、どのモナドでも正しいStateです。

とにかく、技術的な部分:(x, g') <- return $ random gスニペットの意味

(x, g') <- State (\g'' -> (random g, g''))

ここで、モナド アクションが現在の状態g''(g と同じ値を持つ) を取得し、それ (部分) を変更せずに、生成された値を (部分) と共に(..., g'')返すことがわかります。random g(random g, ...)

!を使用しているため、読み取る 必要さえないため、これは少しばかげています。g''random g

だから、私たちは使用しています

do g       <- State (\g'' -> (g'', g''))
   (x, g') <- State (\g'' -> (random g, g''))
   ...

代わりに使用できる場合

do (x, g') <- State (\g'' -> (random g'', g''))
   ...

ライブラリで呼び出される

do (x, g') <- gets random
   ...

さて、混乱は にあるようですdo put g' ; return x。これは、次のように bind-notation に脱糖されます。

{ definitions }
put g'   = State $ \s -> ((), g')
return x = State $ \s -> (x , s )

do put g ; return x 
= { definitions, desugaring }
   (State $ \s -> ((), g'))
   >>= 
   (\_ -> State $ \s -> (x , s ))
= { definition of >>= }
   State $ \s -> let (v,s') = (\s -> ((), g')) s 
                 in runState ((\_ -> State $ \s -> (x , s )) v) s'
= { beta-reduction (application) }
   State $ \s -> let (v,s') = ((), g')
                 in runState (State $ \s -> (x , s )) s'
= { beta-reduction (let) }
   State $ \s -> runState (State $ \s -> (x , s )) g'
= { runState (State y) = y }
   State $ \s -> (\s -> (x , s )) g'
= { beta-reduction }
   State $ \s -> (x , g')

したがって、 の効果はdo put g' ; return x、状態をg'(前のものを上書きして) に変更し、計算の最終値として (と一緒に)s降伏することです。xg'

于 2016-06-19T16:06:31.267 に答える