0

I have this bit of code:

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

And I would like to refactor its signature to be of form:

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

I thought I could equip RVar with MonadState functions:

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

But I am getting this inexplicable error:

 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. Please explain the error and help make the more generic signature possible?

  2. If I wanted to do:

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

How would I implement it? I cannot use uniform any more. Because it locks me to signature RVar a but I really want MonadRandom m => m a, or at the very least Monad m => RVarT m a

Cactus
27.8k10 gold badges74 silver badges165 bronze badges
asked Dec 16, 2015 at 4:33
2
  • You wrote (uniform 0 1 :: RVar Double) but you declared the type of the function to be m (). The monads must match - m must be equal to RVar, which it is not. You may not use the signature (MonadRandom m, MonadState s m) => s -> m () in particular because the uniform function is implemented for RVar, not for any MonadRandom. Commented Dec 16, 2015 at 16:50
  • You can have MonadState s m => s -> RVarT m (), of course, simply use uniformT :: Distribution Uniform a => a -> a -> RVarT m a. Commented Dec 16, 2015 at 16:51

1 Answer 1

3

uniform is not polymorphic in the monad it runs in (in other words, you can't run it in any choice of m if all you know is that RandomSource m s):

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

However, if you have a source of entropy, you can runRVar it in any m if RandomSource m s:

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

which means you can write foo with your desired type signature as

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
answered Dec 17, 2015 at 8:18
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.