{-# OPTIONS -fglasgow-exts #-}

module Control.Monad.Random
( Rand
, runRand
, evalRand
, RandT
, runRandT
, evalRandT
, MonadRandom(..)
) where

import System.Random
import Control.Monad
import Control.Monad.State

class RandomGen g => MonadRandom m g | m -> g where
  getRandom  :: Random a => m a
  getRandomR :: Random a => (a, a) -> m a

newtype Rand g a = R{ unR :: State g a }
   deriving (Functor, Monad, MonadFix)

runRand :: RandomGen g => Rand g a -> g -> (a, g)
runRand = runState . unR

evalRand :: RandomGen g => Rand g a -> g -> a
evalRand = evalState . unR


instance RandomGen g => MonadRandom (Rand g) g where
  getRandom        = R $ State $ random
  getRandomR range = R $ State $ randomR range



newtype RandT g m a = RT{ unRT :: StateT g m a }
   deriving (Functor, Monad, MonadFix, MonadTrans, MonadIO, MonadPlus)

runRandT :: (Monad m, RandomGen g) => RandT g m a -> g -> m (a, g)
runRandT = runStateT . unRT

evalRandT :: (Monad m, RandomGen g) => RandT g m a -> g -> m a
evalRandT = evalStateT . unRT

instance (Monad m, RandomGen g) => MonadRandom (RandT g m) g where
   getRandom        = RT $ StateT $ return . random
   getRandomR range = RT $ StateT $ return . randomR range
