MonadRandom (empty) → 0.1.0
raw patch · 5 files changed
+264/−0 lines, 5 filesdep +basedep +mtlbuild-type:Customsetup-changed
Dependencies added: base, mtl
Files
- Control/Monad/Random.hs +170/−0
- Control/Monad/Random/Class.hs +41/−0
- LICENSE +38/−0
- MonadRandom.cabal +13/−0
- Setup.hs +2/−0
+ Control/Monad/Random.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances #-}+ +{- |+Copyright : 2006-2007 Cale Gibbard, Russell O'Connor, Dan Doel, Remi Turk, Eric Kidd.+License : OtherLicense+Stability : experimental+Portability : non-portable (multi-parameter type classes, undecidable instances)++A random number generation monad. See+<http://www.haskell.org/haskellwiki/NewMonads/MonadRandom> for the original+version of this code.++The actual interface is defined by+'Control.Monad.Random.Class.MonadRandom'.++[Computation type:] Computations which consume random values.++[Binding strategy:] The computation proceeds in the same fashion as the+identity monad, but it carries a random number generator that may be+queried to generate random values.++[Useful for:] Monte Carlo algorithms and simulating random processes.++-}++module Control.Monad.Random (+ module System.Random,+ module Control.Monad.Random.Class,+ evalRandT,+ runRandT,+ evalRand,+ runRand,+ evalRandIO,+ fromList,+ Rand, RandT -- but not the data constructors+ -- * Example+ -- $RandExample+ ) where+ +import System.Random+import Control.Monad()+import Control.Monad.Identity+import Control.Monad.Random.Class+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Trans()+import Control.Monad.Writer+import Control.Arrow+ +-- | A monad transformer which adds a random number generator to an+-- existing monad.+newtype (RandomGen g) => RandT g m a = RandT (StateT g m a)+ deriving (Functor, Monad, MonadTrans, MonadIO)++liftState :: (MonadState s m) => (s -> (a,s)) -> m a+liftState t = do v <- get+ let (x, v') = t v+ put v'+ return x+ +instance (Monad m, RandomGen g) => MonadRandom (RandT g m) where+ getRandom = RandT . liftState $ random+ getRandoms = RandT . liftState $ first randoms . split+ getRandomR (x,y) = RandT . liftState $ randomR (x,y)+ getRandomRs (x,y) = RandT . liftState $+ first (randomRs (x,y)) . split++-- | Evaluate a RandT computation using the generator @g@. Note that the+-- generator @g@ is not returned, so there's no way to recover the+-- updated version of @g@.+evalRandT :: (Monad m, RandomGen g) => RandT g m a -> g -> m a+evalRandT (RandT x) g = evalStateT x g+ +-- | Run a RandT computation using the generator @g@, returning the result and+-- the updated generator.+runRandT :: (Monad m, RandomGen g) => RandT g m a -> g -> m (a, g)+runRandT (RandT x) g = runStateT x g+ +-- | A basic random monad.+newtype Rand g a = Rand (RandT g Identity a)+ deriving (Functor, Monad, MonadRandom)+ +-- | Evaluate a random computation using the generator @g@. Note that the+-- generator @g@ is not returned, so there's no way to recover the+-- updated version of @g@.+evalRand :: (RandomGen g) => Rand g a -> g -> a+evalRand (Rand x) g = runIdentity (evalRandT x g)+ +-- | Run a random computation using the generator @g@, returning the result+-- and the updated generator.+runRand :: (RandomGen g) => Rand g a -> g -> (a, g)+runRand (Rand x) g = runIdentity (runRandT x g)+ +-- | Evaluate a random computation in the IO monad, using the random number+-- generator supplied by 'System.Random.getStdRandom'.+evalRandIO :: Rand StdGen a -> IO a+evalRandIO (Rand (RandT x)) = getStdRandom (runIdentity . runStateT x)++-- | Sample a random value from a weighted list. The total weight of all+-- elements must not be 0.+fromList :: (MonadRandom m) => [(a,Rational)] -> m a+fromList [] = error "MonadRandom.fromList called with empty list"+fromList [(x,_)] = return x+fromList xs = do+ -- TODO: Do we want to be able to use floats as weights?+ -- TODO: Better error message if weights sum to 0.+ let s = (fromRational (sum (map snd xs))) :: Double -- total weight+ cs = scanl1 (\(_,q) (y,s') -> (y, s'+q)) xs -- cumulative weight+ p <- liftM toRational $ getRandomR (0.0,s)+ return . fst . head $ dropWhile (\(_,q) -> q < p) cs++instance (MonadRandom m) => MonadRandom (StateT s m) where+ getRandom = lift getRandom+ getRandomR = lift . getRandomR+ getRandoms = lift getRandoms+ getRandomRs = lift . getRandomRs+ +instance (MonadRandom m, Monoid w) => MonadRandom (WriterT w m) where+ getRandom = lift getRandom+ getRandomR = lift . getRandomR+ getRandoms = lift getRandoms+ getRandomRs = lift . getRandomRs+ +instance (MonadRandom m) => MonadRandom (ReaderT r m) where+ getRandom = lift getRandom+ getRandomR = lift . getRandomR+ getRandoms = lift getRandoms+ getRandomRs = lift . getRandomRs+ +instance (MonadState s m, RandomGen g) => MonadState s (RandT g m) where+ get = lift get+ put = lift . put+ +instance (MonadReader r m, RandomGen g) => MonadReader r (RandT g m) where+ ask = lift ask+ local f (RandT m) = RandT $ local f m+ +instance (MonadWriter w m, RandomGen g, Monoid w) => MonadWriter w (RandT g m) where+ tell = lift . tell+ listen (RandT m) = RandT $ listen m+ pass (RandT m) = RandT $ pass m++instance MonadRandom IO where+ getRandom = randomIO+ getRandomR = randomRIO+ getRandoms = fmap randoms newStdGen+ getRandomRs b = fmap (randomRs b) newStdGen++{- $RandExample++The @die@ function simulates the roll of a die, picking a number between 1+and 6, inclusive, and returning it in the 'Rand' monad. Notice that this+code will work with any source of random numbers @g@.++>die :: (RandomGen g) => Rand g Int+>die = getRandomR (1,6)++The @dice@ function uses @replicate@ and @sequence@ to simulate the roll of+@n@ dice.++>dice :: (RandomGen g) => Int -> Rand g [Int]+>dice n = sequence (replicate n die)++To extract a value from the 'Rand' monad, we can can use 'evalRandIO'.++>main = do+> values <- evalRandIO (dice 2)+> putStrLn (show values)++-}
+ Control/Monad/Random/Class.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances #-}++{- |+Copyright : 2006-2007 Cale Gibbard, Russell O'Connor, Dan Doel, Remi Turk, Eric Kidd.+License : OtherLicense+Stability : experimental+Portability : non-portable (multi-parameter type classes, undecidable instances)++A type class for random number generation monads. See+<http://www.haskell.org/haskellwiki/NewMonads/MonadRandom> for the original+version of this code.++Instances of this type class include 'Control.Monad.Random.Rand' and+monads created using 'Control.Monad.Random.RandT'.++-}++module Control.Monad.Random.Class (+ MonadRandom,+ getRandom,+ getRandomR,+ getRandoms,+ getRandomRs,+ ) where++import System.Random++-- | An interface to random number generation monads.+class (Monad m) => MonadRandom m where+ -- | Return a randomly-selected value of type @a@. See+ -- 'System.Random.random' for details.+ getRandom :: (Random a) => m a+ -- | Return an infinite stream of random values of type @a@. See+ -- 'System.Random.randoms' for details.+ getRandoms :: (Random a) => m [a]+ -- | Return a randomly-selected value of type @a@ in the range+ -- /(lo,hi)/. See 'System.Random.randomR' for details.+ getRandomR :: (Random a) => (a,a) -> m a+ -- | Return an infinite stream of randomly-selected value of type @a@+ -- in the range /(lo,hi)/. See 'System.Random.randomRs' for details.+ getRandomRs :: (Random a) => (a,a) -> m [a]
+ LICENSE view
@@ -0,0 +1,38 @@+MonadRandom library.+Copyright 2006-2007 Cale Gibbard. All rights reserved.+Copyright 2006 Russell O'Connor, Dan Doel, Remi Turk. All rights reserved.+Copyright 2007 Eric Kidd. All rights reserved.++[This code was originally posted by Cale Gibbard to the Haskell Wiki,+remnants of which can be seen at:++http://web.archive.org/web/20070615071737/http://haskell.org/hawiki/MonadRandom++This code was relicensed from a 2-clause BSD license to the license below+by Cale Gibbard's statement at:++http://www.haskell.org/haskellwiki/User:CaleGibbard++The code was then moved to:++http://www.haskell.org/haskellwiki/NewMonads/MonadRandom++New additions by several people were provided under the implicit license at:++http://www.haskell.org/haskellwiki/HaskellWiki:Copyrights++So, in theory, this license should apply to everything in this library.]++Permission is hereby granted, free of charge, to any person obtaining this+work (the "Work"), to deal in the Work without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Work, and to permit+persons to whom the Work is furnished to do so.++THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS IN+THE WORK.
+ MonadRandom.cabal view
@@ -0,0 +1,13 @@+Name: MonadRandom+Version: 0.1.0+Synopsis: Random-number generation monad.+Description: Support for computations which consume random values.+License: OtherLicense+License-file: LICENSE+Category: Control+Author: Cale Gibbard and others+Maintainer: Eric Kidd <haskell@randomhacks.net>+Stability: experimental+Build-Depends: base, mtl+Exposed-modules: Control.Monad.Random.Class, Control.Monad.Random+ghc-options: -Wall -fno-warn-orphans -O
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain