私はあなたが混乱していると思います
(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
降伏することです。x
g'