I’m happy to announce the release of
MonadRandom-0.5, a package which provides a convenient monadic interface for random number generation in the style of
Rand monad (essentially a state monad that threads through a generator), a monad transformer variant called
RandT, and a
RandomMonad class allowing the use of random generation operations in monad stacks containing
This release has quite a few small additions as well as a big module reorganization. However, thanks to module re-exports, most existing code using the library should continue to work with no changes; the major version bump reflects the large reorganization and my resultant inability to 100% guarantee that existing user code will not break. If your code does break, please let me know—I would be happy to help you fix it, or simply to know about it so I can help other users.
Here are a few of the biggest changes that may be of interest to users of the library:
MonadInterleaveclass (see #20), which is a big improvement over
MonadSplit. It provides a method
interleave :: m a -> m a, which works by splitting the generator, running its argument using one half of the generator, and using the other half as the final state of the resulting action (replacing whatever the final generator state otherwise would have been). This can be used, for example, to allow random computations to run in parallel, or to create lazy infinite structures of random values. In the example below, the infinite tree
randTreecannot be evaluated lazily: even though it is cut off at two levels deep by
hew 2, the random value in the right subtree still depends on generation of all the random values in the (infinite) left subtree, even though they are ultimately unneeded. Inserting a call to
interleave, as in
randTreeI, solves the problem: the generator splits at each
Node, so random values in the left and right subtrees are generated independently.
data Tree = Leaf | Node Int Tree Tree deriving Show hew :: Int -> Tree -> Tree hew 0 _ = Leaf hew _ Leaf = Leaf hew n (Node x l r) = Node x (hew (n-1) l) (hew (n-1) r) randTree :: Rand StdGen Tree randTree = Node <$> getRandom <*> randTree <*> randTree randTreeI :: Rand StdGen Tree randTreeI = interleave $ Node <$> getRandom <*> randTreeI <*> randTreeI >>> hew 2 <$> evalRandIO randTree Node 2168685089479838995 (Node (-1040559818952481847) Leaf Leaf) (Node ^CInterrupted. >>> hew 2 <$> evalRandIO randTreeI Node 8243316398511136358 (Node 4139784028141790719 Leaf Leaf) (Node 4473998613878251948 Leaf Leaf)
RandT(thanks to Koz Ross), allowing it to be used in conjunction with e.g. mutable vectors.
- New and improved random selection functions:
fromListnow raises an error when the total weight of elements is zero.
- The type of
uniformis generalized to work over any
- New operations
uniformMayhave been added.
fromListbut generalized to work over any
Mayvariants, of course, return a
Mayberesult instead of raising an error.
New lazy vs strict variants of the
Randmonad. If you import
Control.Monad.Trans.Randomyou get the
Lazyvariant re-exported by default, but you can explicitly import
.Strictif you want. They provide the exact same API, but
Lazyis implemented with a lazy state monad and
Strictwith a strict one. To be honest it’s not clear what difference this might make, but since the distinction is already there with the underlying state monad for free, why not provide it?
Although there was some discussion of generalizing
MonadRandom to work for a wider range of underlying generators (see the comments on my previous blog post and the discussion on issue #26), I decided to punt on that for now. It seems rather complicated, and that there are already good alternatives like the very nice
random-fu package, so I decided to keep things simple for this release. I’m still open to proposals for generalizing future releases.