0

我有這段代碼:使用MonadRandom與MonadState

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() 

我以爲我可以裝備RVarMonadState功能:

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

and write:

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() 
    

我將如何實現呢?我不能再使用uniform。因爲它鎖定我的簽名RVar a,但我真的想MonadRandom m => m a, 或者至少是Monad m => RVarT m a

+0

你寫'(統一0 1 :: RVAR雙人間)',但你聲明的函數的類型爲'M()' 。 monads必須匹配 - 「m」必須等於「RVar」,而不是。你可以不使用'(MonadRandom m,MonadState s m)=> s - > m()'簽名,因爲'uniform'函數是爲RVar實現的,而不是用於任何MonadRandom。 – user2407038

+0

你可以有'MonadState s m => s - > RVarT m()',當然,只需使用'uniformT :: Distribution Uniform a => a - > a - > RVarT m a'。 – user2407038

回答

3

uniform是不是在它運行的單子多態(換句話說,你不能在任何m選擇運行如果你知道的是,RandomSource m s):

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

但是,如果你有熵的來源,你可以runRVar它在任何m如果RandomSource 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