我想用给定的均值和标准差对正态分布进行抽样。我知道如何在各种上下文(例如Data.Random.Rvar或Data.Random.MonadRandom)中执行此操作。
但是,我的函数的上下文是Control.Monad.MonadRandom,我想保持这种方式,因为我的整个项目都使用Control.Monad.MonadRandom。
有没有办法做到这一点,您能帮我吗?
代码如下所示。模式只是Data.Vector Double的别名,而Weights是Data.Vector(Data.Vector Double)的别名(即矩阵)
train :: MonadRandom m => [Pattern] -> Int -> m Weights
train pats nr_hidden = do
ws_start <- ws_start''
foldM updateWS ws_start pats
where ws_start' = take p (repeat $ take nr_hidden $ repeat $ (normal 0.0 0.01))
ws_start'' = vector2D <$> (sequence $ map sequence ws_start')
p = length pats
谢谢你。
最佳答案
快速答案
如何在Data.Random.RVar
中使用Control.Monad.MonadRandom
?
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Monad.Random as CMR
import Data.Random as DR
import Data.Word (Word32)
gimmeRandom :: forall m . CMR.MonadRandom m => m Int
gimmeRandom = do
r <- runRVar (uniform 0 100) (getRandom :: m Word32)
return r
解释
实际上,您想在形式相似的Monad内以相似的语义运行Monad。
Data.Random.MonadRandom
和Control.Monad.Random
在形式上有所不同,因为它们在不同的地方独立定义,并且都不是另一个的实例(没有instance DR.MonadRandom m => CMR.MonadRandom m
或相反)。 假设您在
Control.Monad.Random
接口(interface)中有一些代码:import Control.Monad.Random as CMR
gimmeRandom :: CMR.MonadRandom m => m Int
gimmeRandom = do
r <- getRandomR (0, 100)
return r
我们可以像
evalRand gimmeRandom StdGen
这样运行,这为我们提供了Int
。现在,您要使用
getRandomR
提供的许多可用发行版之一,而不是Data.Random
。对于此示例,我们将尝试将
getRandomR (0, 100)
替换为uniform 0 100 :: RVar Int
。我们如何在Int
环境中从该RVar Int
中获取CMR.MonadRandom
?我们要运行
RVar
monad,正如语义上暗示的那样,我们可能必须为其提供一个随机数源。我们正在寻找CMR的像evalRand这样的monad转义函数。这些转义功能的类型为m a -> someStuffNeededToRunTheMonad -> a
。在docs about RVar中,有一个示例:
-- In a monad, using a RandomSource:
runRVar (uniform 1 100) DevRandom :: IO Int
让我们检查
runRVar
:runRVar :: RandomSource m s => RVar a -> s -> m a
是的,这是一种转义函数:给定
RVar
和随机数源,它将返回我们自己的monad RVar
中m
的随机结果。但是,这需要有一个instance RandomSource m s
,它表明s
是我们monad m
的随机性源。让我们寻找那个实例。我们的monad
m
是什么?我们要在RVar
中运行gimmeRandom
,因此monad是CMR.MonadRandom m => m
(所有实现CMR.MonadRandom
的monad)。什么是随机源s
?还没有头绪。 Let us look in the docs存在哪些RandomSource
实例:RandomSource IO DevRandom
...
Monad m0 => RandomSource m0 (m0 Word32)
Monad m0 => RandomSource m0 (m0 Word64)
...
啊哈!这表示任何monad
m0
都是RandomSource
的实例,并带有来自此monad的值(例如m0 Word32
)。当然,这也适用于我们的monad CMR.MonadRandom
。我们还可以看到s
,m0 Word32
必须是由随机性源生成的随机值。我们应该以
s
中的runRVar (uniform 0 100) s
传递什么?在我们的monad中生成随机数的某种东西,类型为CMR.MonadRandom m => m Word32
。什么是CMR
函数来生成任意事物,例如一些Word32
吗? getRandom。所以基本上我们想写:gimmeRandom :: CMR.MonadRandom m => m Int
gimmeRandom = do
r <- runRVar (uniform 0 100) getRandom
return r
嗯,那不会编译:
Could not deduce (RandomSource m (m0 a0))
arising from a use of `runRVar'
from the context (CMR.MonadRandom m)
bound by the type signature for
gimmeRandom :: CMR.MonadRandom m => m Int
RandomSource m (m0 a0)
?奇怪的是,编译器似乎将m
和m0
识别为不同的monad;我们希望它们与RandomSource m0 (m0 Word64)
中的相同。让我们将完整的签名放入该位置:
r <- runRVar (uniform 0 100) (getRandom :: CMR.MonadRandom m => m Word32)
还是一样的错误。这是因为该类型签名中的
m
实际上是实现CMR.MonadRandom
的任何monad,而不一定是我们MonadRandom
类型签名中的gimmeRandom
。(这与 lambda 术语
(\x -> (\x -> f x))
中的阴影概念相同,其中内部\x
是f x
中使用的那个;或者在像∀x . F(x) → ∀x . G(x)
这样的一阶逻辑中,其中x
中的G(x)
是最内部定义的一个,不必相同,甚至与外部∀x
中的类型都不相同;或者实际上在任何其他在内部范围中具有隐藏/阴影变量的编程语言中-只是这里是类型变量阴影)。因此,我们唯一需要做的就是告诉编译器,在
getRandom
调用中,我们不希望将其用于任何MonadRandom
,而只是希望我们在MonadRandom m
类型签名中具有的gimmeRandom
。我们可以使用
ScopedTypeVariables
扩展名来做到这一点:{-# LANGUAGE ScopedTypeVariables #-}
[...]
gimmeRandom :: forall m . CMR.MonadRandom m => m Int
gimmeRandom = do
r <- runRVar (uniform 0 100) (getRandom :: m Word32)
return r
这样就可以从顶层类型签名中准确选择
m
中的getRandom :: m ...
。这样就可以编译并解决了问题:我们可以使用
CMR.MonadRandom m
接口(interface)在代码中使用Data.Random
的发行版。我们可以轻松地用另一个发行版替换MonadRandom
。总结,我们有
uniform
)运行/转义我们要使用的monad runRVar
)runRVar (uniform 0 100) getRandom
进行编译。 如果您想知道为什么我们从可以选择的实例中任意选择
getRandom
,我们只需要以某种形式提供随机性源,Word32是Word32
用作生成其他随机数据的输入之一。关于haskell - 使用Control.Monad.MonadRandom对正态分布进行采样,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13936502/