我有这段代码:
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.
请解释错误并帮助实现更通用的签名?
如果我想这样做:
foo :: (MonadRandom m, MonadState s m) => s -> m ()
我该如何实施?我不能再使用uniform
了。因为它将我锁定为签名RVar a
,但我真的想要MonadRandom m => m a
,
或者至少Monad m => RVarT m a
答案 0 :(得分:3)
uniform
在它运行的monad中不是多态的(换句话说,如果您知道的是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