gpt4 book ai didi

haskell - Monad Transformer (RandT) 内的多个独立 ST/State monad...复杂的包装/展开

转载 作者:行者123 更新时间:2023-12-02 10:48:34 24 4
gpt4 key购买 nike

只是学习如何更深入直观地掌握 monad 和 Transformer;很多看似显而易见的事情对我来说仍然有点棘手,哈哈。

所以我有一个计算存在于 Rand monad 中,但是在其内部,还有另一个“子计算”(或多个)存在于 ST monad(或 State monad,尽管这很重要...... ST 仅用于性能,但我认为 State 有效在这种情况下也是如此)。

整个计算不需要在 ST monad 内...并且这个子计算将以不同的起始状态被多次调用,所以我不想强制整个事情变成 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 = -- ...

基本上一切工作得很好,并且在 mainCompsubComp 中具有完全的引用透明性。

这就是我迄今为止使用 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 = ??

如果我想使用随机种子和其中的 Rand monad,mutateState 的类型应该是什么?我想我可能想使用 RandT g (ST s) () 的返回类型,但是如何使其符合 runST 中预期的类型子组件

最佳答案

使用 monad 转换器,您可以按照添加图层的相反顺序“剥离”图层。因此,如果您有 RandT g (ST s) () 类型的内容,则首先使用 evalRandTrunRandT 消除 RandT,然后然后才调用runST

以下是组合 RandTST 的简单示例:

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,可让您在 RandT StdGen (ST s) a 中嵌入计算 Rand StdGen a 计算。该函数使用 getSplit分割全局计算的种子,并将新的种子输入到子计算中。

{-# 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)

关于haskell - Monad Transformer (RandT) 内的多个独立 ST/State monad...复杂的包装/展开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17516407/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com