在一些 monad 转换器堆栈上使用 runRVar

Usage of runRVar over some monad transformer stack

在下面的例子中:

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 => StateT Int m ()

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