random-fu-0.1.4: Random number generation



This is an experimental interface to support an extensible set of primitives, where a RandomSource will be able to support whatever subset of them they want and have well-founded defaults generated automatically for any unsupported primitives.

The purpose, in case it's not clear, is to decouple the implementations of entropy sources from any particular set of primitives, so that implementors of random variates can make use of a large number of primitives, supported on all entropy sources, while the burden on entropy-source implementors is only to provide one or two basic primitives of their choice.

One challenge I foresee with this interface is optimization - different compilers or even different versions of GHC may treat this interface radically differently, making it very hard to achieve reliable performance on all platforms. It may even be that no compiler optimizes sufficiently to make the flexibility this system provides worth the overhead. I hope this is not the case, but if it turns out to be a major problem, this system may disappear or be modified in significant ways.



data Prim a whereSource

A Prompt GADT describing a request for a primitive random variate. Random variable definitions will request their entropy via these prompts, and entropy sources will satisfy some or all of them. The decomposePrimWhere function extends an entropy source's incomplete definition to a complete definition, essentially defining a very flexible implementation-defaulting system.

Some possible future additions: PrimFloat :: Prim Float PrimInt :: Prim Int PrimPair :: Prim a -> Prim b -> Prim (a :*: b) PrimNormal :: Prim Double PrimChoice :: [(Double :*: a)] -> Prim a

Unfortunately, I cannot get Haddock to accept my comments about the data constructors, but hopefully they should be reasonably self-explanatory.


getPrimWhere :: Monad m => (forall t. Prim t -> Bool) -> (forall t. Prim t -> m t) -> Prim a -> m aSource

This function wraps up the most common calling convention for decomposePrimWhere. Given a predicate identifying "supported" Prims, and a (possibly partial) function that maps those Prims to implementations, derives a total function mapping all Prims to implementations.

decomposePrimWhere :: (forall t. Prim t -> Bool) -> Prim a -> Prompt Prim aSource

This is essentially a suite of interrelated default implementations, each definition making use of only "supported" primitives. It _really_ ought to be inlined to the point where the supported predicate is able to be inlined into it and eliminated.

When inlined sufficiently, it should in theory be optimized down to the static set of best definitions for each required primitive in terms of only supported primitives.

Hopefully it does not impose too much overhead when not inlined.