【问题标题】:Usage of runRVar over some monad transformer stack在某些 monad 变压器堆栈上使用 runRVar
【发布时间】:2015-12-07 04:34:30
【问题描述】:

在以下示例中:

toss :: Double -> RVar Bool
toss p = do
  q <- uniform 0 1
  return $ q <= p

toss' :: MonadRandom m => Double -> m Bool
toss' p = runRVar (toss p) StdRandom


foo :: StateT Int RVar ()
foo = do
    h <- lift $ toss' 0.5
    if h then put 100 else put 0

bar :: StateT Int RVar ()
bar = do
    h <- lift $ toss 0.5
    if h then put 404 else put 200


testFoo :: MonadRandom m => m ((), Int)
testFoo = runRVar (runStateT foo 0) StdRandom

testBar :: MonadRandom m => m ((), Int)
testBar = runRVar (runStateT bar 0) StdRandom

我很困惑:

  1. 为什么 foo 的签名被强制为 StateT Int RVar (),即使 toss' 对某些 MonadRandom m 有签名 m Bool

  2. 为什么testFoo 必须与一些StdRandom 一起运行,即使toss' 已经runRVarStdRandom。从类型的角度来看这是有道理的,但最终使用了哪个StdRandom?如果这个问题有任何意义。

  3. 是否可以将foo的签名重写为MonadRandom m =&gt; StateT Int m ()

【问题讨论】:

  • runRVar 的类型非常一般 - 在这种情况下,当您在 foo 和 @987654339 内部使用 toss' 时,第一个 runRVar 将被实例化为 RVar Bool -&gt; StdRandom -&gt; RVar Bool 类型@。而这个功能只是身份(或应该是)。在任何情况下,StdRandom 都不会“做”任何事情 - 当您编写 runRVar ... StdRandom 时,它只是意味着使用 MonadRandom 接口作为随机源。

标签: haskell monads monad-transformers


【解决方案1】:
  1. 启用单态限制时(默认启用),所有类型的顶级绑定器都将被推断为单态。
  2. 您应该像在bar 中那样将RVar 添加到monad 堆栈中。 MonadRandom 太笼统了。 StdRandom 只是一个数据构造函数,所以它没有特定的状态。 random-fu 应该自动处理更新状态。
  3. 只需添加签名即可。见 1。

【讨论】:

  • 我很抱歉澄清一下,你是说通过设置NoMonomorphismRestriction,我现在看到我可以写bar :: MonadRandom m =&gt; StateT Int m ()但是我还是应该写StateT Int RVar (),因为MonadRandom m 太笼统了?你是说StdRandom 只是为了满足类型检查器的需要,实际上并没有初始化随机种子对吗?
  • 是的,差不多。通过编写 RVar,您无需执行 runRVar inside StateT 并且只需从外部提供一个随机生成器即可。这还具有使更改使用的随机数生成器更容易的效果(您只需传递/编辑一次,而不是替换所有出现的 StdRandom)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-18
  • 2014-05-03
  • 1970-01-01
相关资源
最近更新 更多