将MonadRandom与MonadState一起使用

时间:2015-12-16 04:33:05

标签: haskell monads monad-transformers algebraic-data-types state-monad

我有这段代码:

import Data.Random
import Control.Monad.State

foo :: s -> StateT s RVar ()
foo s = do
  p <- lift $ (uniform 0 1 :: RVar Double)
  if p > 0.5 then put s else return ()

我想重构它的签名:

foo :: (MonadState s m, RandomSource m s) => s -> m ()

我以为我可以使用RVar函数装备MonadState

{- LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
instance MonadState s m => MonadState s (RVarT m) where
  get   = lift get
  put   = lift . put
  state = lift . state

并写:

foo :: (MonadState s m, RandomSource m s) => s -> m ()
foo s = do
  p <- (uniform 0 1 :: RVar Double)
  if p > 0.5 then put s else return ()

但我得到了这个莫名其妙的错误:

    Couldn't match type ‘m’
                   with ‘t0 (RVarT Data.Functor.Identity.Identity)’
      ‘m’ is a rigid type variable bound by
          the type signature for
            foo :: (MonadState s m, RandomSource m s) => s -> m ()
          at ApproxMedian.hs:99:8
    Expected type: m Double
      Actual type: t0 (RVarT Data.Functor.Identity.Identity) Double
    Relevant bindings include
      foo :: s -> m () (bound at ApproxMedian.hs:100:1)
    In a stmt of a 'do' block: p <- lift $ (uniform 0 1 :: RVar Double)
    In the expression:
      do { p <- lift $ (uniform 0 1 :: RVar Double);
           if p > 0.5 then put s else return () }
    In an equation for ‘foo’:
        foo s
          = do { p <- lift $ (uniform 0 1 :: RVar Double);
                 if p > 0.5 then put s else return () }
Failed, modules loaded: Core, Statistics.
  1. 请解释错误并帮助实现更通用的签名?

  2. 如果我想这样做:

    foo :: (MonadRandom m, MonadState s m) => s -> m ()
    
  3. 我该如何实施?我不能再使用uniform了。因为它将我锁定为签名RVar a,但我真的想要MonadRandom m => m a, 或者至少Monad m => RVarT m a

1 个答案:

答案 0 :(得分:3)

uniform在它运行的monad中不是多态的(换句话说,如果您知道的是m),则无法在RandomSource m s的任何选项中运行它:

uniform :: Distribution Uniform a => a -> a -> RVar a

但是,如果你有熵源,如果有runRVar,你可以在任何mRandomSource m s

runRVar :: RandomSource m s => RVar a -> s -> m a

这意味着您可以将foo写为所需的类型签名

foo :: (MonadState s m, RandomSource m s) => s -> m ()
foo s = do
  p <- runRVar (uniform 0 1 :: RVar Double) s
  when (p > 0.5) $ put s