我想用给定的均值和标准差对正态分布进行抽样。我知道如何在各种上下文(例如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.MonadRandomControl.Monad.Random在形式上有所不同,因为它们在不同的地方独立定义,并且都不是另一个的实例(没有instance DR.MonadRandom m => CMR.MonadRandom m或相反)。
  • Monad具有相似的语义,因为它们都从某些随机性源中提供随机数,因此期望我们可以以某种方式组合它们是有道理的。

  • 假设您在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 RVarm的随机结果。但是,这需要有一个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。我们还可以看到sm0 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)?奇怪的是,编译器似乎将mm0识别为不同的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))中的阴影概念相同,其中内部\xf 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

    总结,我们有
  • 确定我们使用来自不同软件包的两个不同的monad,但语义相同/重叠
  • 发现了如何在我们自己的内部(使用uniform)运行/转义我们要使用的monad
  • 通过查看其转义函数的类型限制和为这些
  • 提供的实例来找出要传递给转义函数的内容
  • 编写正确的代码(runRVar)
  • 通过说出应使用哪种精确的monad runRVar (uniform 0 100) getRandom进行编译。


  • 如果您想知道为什么我们从可以选择的实例中任意选择getRandom,我们只需要以某种形式提供随机性源,Word32是Word32用作生成其他随机数据的输入之一。

    关于haskell - 使用Control.Monad.MonadRandom对正态分布进行采样,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13936502/

    10-09 02:53