module Random where
import System.Random (StdGen)
import qualified System.Random as R
import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Identity
data RandT m a = RandT { runRandT :: (StdGen -> m (a,StdGen)) }
type Rand = RandT Identity
runRand :: Rand a -> IO a
runRand = (return . runIdentity) <=< randAsIO
randAsIO :: Monad m => RandT m a -> IO (m a)
randAsIO i = R.newStdGen >>= return . (fst <$>) . runRandT i
withGen :: Monad m => (StdGen -> (a,StdGen)) -> RandT m a
withGen f = RandT (return . f)
instance Monad m => Functor (RandT m) where
fmap f a = pure f <*> a
instance Monad m => Applicative (RandT m) where
pure = return
(<*>) = ap
instance Monad m => Monad (RandT m) where
return a = RandT $ \g -> return (a, g)
(RandT a) >>= f = RandT $ \g -> do
(a', g') <- a g
runRandT (f a') g'
instance MonadTrans RandT where
lift a = RandT $ \g -> do
a' <- a
return (a', g)
instance MonadIO m => MonadIO (RandT m) where
liftIO = lift.liftIO
random :: (Monad m, R.Random a) => RandT m a
random = withGen R.random
randomR :: (Monad m, R.Random a) => (a,a) -> RandT m a
randomR range = withGen $ R.randomR range
randoms :: (Monad m, R.Random a) => RandT m [a]
randoms = RandT $ \g ->
let (og,ng) = R.split g in return (R.randoms og, ng)
randomRs :: (Monad m, R.Random a) => (a,a) -> RandT m [a]
randomRs range = RandT $ \g ->
let (og, ng) = R.split g in return (R.randomRs range og, ng)
-----
-- 'pluck' a random item from a list
pluck :: Monad m => [a] -> RandT m (Maybe a, [a])
pluck [] = return (Nothing, [])
pluck as = do
n <- randomR (0, (length as)-1)
return (Just (as !! n), (take n as) ++ (drop (n+1) as))
-- shuffle a list
shuffle :: Monad m => [a] -> RandT m [a]
shuffle [] = return []
shuffle as = do
(Just a, rest) <- pluck as
shufR <- shuffle rest
return (a:shufR)