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

Я думал, что я мог бы оборудовать 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() 
    

Как бы это осуществить? Я не могу использовать uniform. Потому что он блокирует меня подпись RVar a, но я действительно хочу MonadRandom m => m a, или по крайней мере Monad m => RVarT m a

+0

Вы писали '(Uniform 0 1 :: RVar Double)', но вы объявили тип функции, чтобы быть 'м()' , Монады должны совпадать - '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