在ST monad中跟踪函数之间的几个引用的好方法?

Tom*_*Tom 8 monads state haskell

我正在编写一些代码(Metropolis-Hastings MCMC采样器),它将使用随机数生成器,并基于此修改数组和其他可能的结构.

我最初的想法是使用ST monad,这样我就可以使用ST数组和mersenne-random-pure64包,保持PureMT生成器成为状态的一部分.

但是我希望能够将一些工作拆分成单独的辅助函数(例如,在给定范围内对随机整数进行采样,更新数组结构,以及可能更复杂的事情).要做到这一点,我想我需要将对PureMT gen和数组的引用传递给所有函数,如果我需要存储更多状态,这很快就会变得非常难看.

我的直觉是将所有状态组合成一个我可以在任何地方访问的单一数据类型,因为我会通过定义一个新的数据类型来使用State monad,但我不知道这对ST monad是否可行,或者正确的方式去做.

做这种事情有什么好的模式吗?我希望尽可能保持一般性,因为我可能需要添加额外的状态并在现有部分周围构建更多的monadic代码.

我试过寻找ST monad代码的例子,但它似乎没有被Real World Haskell所涵盖,并且haskell wiki示例非常简短.

谢谢!

C. *_*ann 10

我的直觉是将所有状态组合成一个我可以在任何地方访问的单一数据类型,因为我会通过定义一个新的数据类型来使用State monad,但我不知道这对ST monad是否可行,或者正确的方式去做.

做这种事情有什么好的模式吗?我希望尽可能保持一般性,因为我可能需要添加额外的状态并在现有部分周围构建更多的monadic代码.

在这里意识到的关键点是,你正在使用它是完全无关紧要的ST.该ST文献本身只是普通的值,你需要访问在不同的地方,但你并不真的想改变他们!可变性发生在ST,但STRef值和诸如此类基本上是只读的.他们的名字指向可变数据.

当然,Readermonad用于对周围环境进行只读访问.对所有函数的引用的丑陋传递正是它为你做的,但因为你已经在ST,你可以把它作为monad变换器.举个简单的例子,您可以这样做:

newtype STEnv s e a = STEnv (ReaderT e (ST s) a)
    deriving (Functor, Applicative, Monad)

runEnv :: STEnv s e a -> ST s e -> ST s a
runEnv (STEnv r) e = runReaderT r =<< e

readSTEnv :: (e -> STRef s a) -> STEnv s e a
readSTEnv f = STEnv $ lift . readSTRef . f =<< ask

writeSTEnv :: (e -> STRef s a) -> a -> STEnv s e ()
writeSTEnv f x = STEnv $ lift . flip writeSTRef x . f =<< ask
Run Code Online (Sandbox Code Playgroud)

为了更加通用,您可以抽象出引用类型的详细信息,并将其转换为具有可变引用的一般"环境"monad.


scl*_*clv 5

你可以像IO monad一样使用ST monad,记住你只能获得数组和引用而没有其他IO好东西.就像IO一样,如果要在计算过程中透明地处理某些状态,可以在其上层叠StateT.