gpt4 book ai didi

haskell - 使用 Control.Monad.MonadRandom 对正态分布进行采样

转载 作者:行者123 更新时间:2023-12-04 07:40:38 36 4
gpt4 key购买 nike

我想用给定的均值和标准差对正态分布进行采样。我知道如何在 Data.Random.Rvar 或 Data.Random.MonadRandom 等各种上下文中做到这一点。
但是,我的函数的上下文是 Control.Monad.MonadRandom,我想保持这种状态,因为我的整个项目都使用 Control.Monad.MonadRandom。

有什么办法可以做到这一点,你能帮我做到这一点吗?

下面是代码的样子。 Pattern 只是 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 或其他方式)。
  • Monads 具有相似的语义,因为它们都提供来自某个随机源的随机数,因此期望我们可以以某种方式组合它们是有道理的。

  • 假设您在 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。我们还可以看到 sm0 Word32 一定是随机源生成的随机值。

    我们应该将什么作为 s 中的 runRVar (uniform 0 100) s 传入?在我们的 monad 中生成随机数的东西,类型为 CMR.MonadRandom m => m Word32 的东西。什么是 CMR 函数来生成任意事物,例如一些 Word32getRandom。所以基本上我们想写:
    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) 之类的一阶逻辑中,其中 x5 和 G(x)5 中最需要的定义是 ∀x6甚至不是与外部 getRandom 中的类型相同的类型;或者实际上在任何其他具有内部作用域变量隐藏/阴影的编程语言中 - 只是这里是类型变量阴影)。

    所以我们唯一要做的就是告诉编译器在 MonadRandom 调用中,我们不希望它是针对任何 MonadRandom m 的,而是针对我们在 gimmeRandom 类型签名中拥有的 ScopedTypeVariables

    我们可以使用 m 扩展名来做到这一点:
    {-# LANGUAGE ScopedTypeVariables #-}

    [...]

    gimmeRandom :: forall m . CMR.MonadRandom m => m Int
    gimmeRandom = do
    r <- runRVar (uniform 0 100) (getRandom :: m Word32)
    return r

    这使得 getRandom :: m ... 中的 CMR.MonadRandom m 恰好是从顶级类型签名中选择的 Data.Random

    这确实编译并解决了问题:我们可以使用 MonadRandom 接口(interface)在代码中使用来自 uniform 的分布。我们可以很容易地用另一个发行版替换 runRVar

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


  • 如果你想知道为什么我们从我们可以选择的实例中随意选择 Word32,我们只需要以某种形式给出随机源,而 Word32 是 Data.Random 作为生成其他随机内容的输入之一。

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

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