在某些monad变换器堆栈上使用runRVar

时间:2015-12-07 04:34:31

标签: haskell monads monad-transformers

在以下示例中:

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'对某些m Bool具有签名MonadRandom m

  2. 为什么testFoo必须与某些StdRandom一起运行,即使toss'runRVar StdRandom。从类型的角度来看,它是有意义的,但StdRandom最终被使用了哪些?如果这个问题有意义的话。

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

1 个答案:

答案 0 :(得分:4)

  1. 当启用单态限制时(默认情况下处于启用状态),所有类型的顶级绑定器都将被推断为单态。
  2. 您应该像RVar中一样将bar添加到monad堆栈。 MonadRandom过于笼统。 StdRandom只是一个数据构造函数,因此它没有特定的状态。 random-fu应自动处理更新状态。
  3. 只需添加签名即可。见1.