3

モナドとトランスフォーマーをより深く直感的に理解する方法を学んでいます。当たり前のように思える多くのことは、私にはまだちょっとトリッキーです(笑)。

したがって、Randモナド内に存在する計算がありますが、その内部には、モナド内に存在する別の「サブ計算」(または複数)がありますST(またはStateモナド、それはすべて重要です...STパフォーマンスのためだけですが、うまくいくと思いStateますこのコンテキストでも同様です)。

計算全体がモナド内にある必要はありませんST...そして、このサブ計算は異なる開始状態で複数回呼び出されるので、全体を に強制したくありませんST(それが慣用的な方法でない限り) .

ランダム性がない場合、構造は次のようになります。

main = print mainComp

mainComp :: Int
mainComp = otherComp + (subComp 1) + (subComp 2)

subComp :: Int -> Int
subComp n = runST $ do
  -- generate state based on n
  -- ...
  replicateM_ 100 mutateState
  -- ...
  -- eventually returns an ST s Int

mutateState :: ST s ()
mutateState = -- ...

基本的に物事はうまく機能し、 と には完全な参照透過性がmainCompありsubCompます。

これは私がこれまで使ってきた方法ですRand-

main = (evalRandIO mainComp) >>= print

mainComp :: (RandomGen g) => Rand g Int
mainComp = do
  subResultA <- subComp 1
  subResultB <- subComp 2
  return $ otherComp + subResultA + subResultB

subComp :: (RandomGen g) => Int -> Rand g Int
subComp = return $ runST $ do           -- is this ok to just throw in return?
  -- generate state based on n
  -- ...
  replicateM_ 100 mutateState
  -- ...
  -- eventually returns an ST s Int (??)

mutateState :: ??
mutateState = ??

ランダムシードとその中でモナドmutateStateを使用したい場合、 の型は何ですか? Randの戻り値の型を使用したいと思うかもしれませんが、それをinRandT g (ST s) ()で期待される型に適合させるにはどうすればよいですか?runSTsubComp

4

1 に答える 1

1

モナドトランスフォーマーを使用すると、レイヤーを追加した逆の順序でレイヤーを「剥がす」ことができます。したがって、 型の何かがある場合は、 orRandT g (ST s) ()を使用して RandT を削除することから始めてから、を呼び出します。evalRandTrunRandTrunST

RandTとを組み合わせた簡単な例を次に示しSTます。

import Data.STRef
import System.Random

import Control.Monad
import Control.Monad.Trans
import Control.Monad.ST
import Control.Monad.Random
import Control.Monad.Random.Class

stNrand :: RandT StdGen (ST s) Int
stNrand = do
    ref <- lift $ newSTRef 0
    i <- getRandomR (0,10)
    lift $ writeSTRef ref i
    lift $ readSTRef ref

main :: IO ()
main = putStrLn . show $ runST $ evalRandT stNrand (mkStdGen 77)

編集:これは拡張バージョンで、計算を計算runSTBelowRandに埋め込むことができる機能を備えています。この関数はgetSplitを使用してグローバル計算のシードを分割し、新しいシードをサブ計算に供給します。RandT StdGen (ST s) aRand StdGen a

{-# LANGUAGE RankNTypes #-}

import Data.STRef
import System.Random

import Control.Monad
import Control.Monad.Trans
import Control.Monad.ST
import Control.Monad.Random
import Control.Monad.Random.Class

stNrand :: RandT StdGen (ST s) Int
stNrand = do
    ref <- lift $ newSTRef 0
    i <- getRandomR (0,10)
    lift $ writeSTRef ref i
    lift $ readSTRef ref

runSTBelowRand :: (forall s. RandT StdGen (ST s) a) -> Rand StdGen a
runSTBelowRand r = do
    splittedSeed <- getSplit
    return $ runST $ evalRandT r splittedSeed

globalRand :: Rand StdGen (Int,Int)
globalRand = do
    i1 <- runSTBelowRand stNrand
    -- possibly non-ST stuff here
    i2 <- runSTBelowRand stNrand
    return (i1,i2)

main :: IO ()
main = putStrLn . show $ evalRand globalRand (mkStdGen 77)
于 2013-07-07T22:22:49.517 に答える