MonadRandom 0.5 released
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 transformers
and mtl
: a 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 RandT
.
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:
-
A new
MonadInterleave
class (see #20), which is a big improvement overMonadSplit
. It provides a methodinterleave :: 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 treerandTree
cannot be evaluated lazily: even though it is cut off at two levels deep byhew 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 tointerleave
, as inrandTreeI
, solves the problem: the generator splits at eachNode
, 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)
-
A new
PrimMonad
instance forRandT
(thanks to Koz Ross), allowing it to be used in conjunction with e.g. mutable vectors. -
New and improved random selection functions:
-
fromList
now raises an error when the total weight of elements is zero. -
The type of
uniform
is generalized to work over anyFoldable
. -
New operations
weighted
,weightedMay
,fromListMay
, anduniformMay
have been added.weighted
is likefromList
but generalized to work over anyFoldable
. TheMay
variants, of course, return aMaybe
result instead of raising an error.
-
-
New lazy vs strict variants of the
Rand
monad. If you importControl.Monad.Random
orControl.Monad.Trans.Random
you get theLazy
variant re-exported by default, but you can explicitly import.Lazy
or.Strict
if you want. They provide the exact same API, butLazy
is implemented with a lazy state monad andStrict
with 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.
For a full rundown of changes in 0.5, see the change log. Comments, questions, and bug reports are always welcome either as a comment on this blog post or on the GitHub issue tracker.