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 where
- PrimWord8 :: Prim Word8
- PrimWord16 :: Prim Word16
- PrimWord32 :: Prim Word32
- PrimWord64 :: Prim Word64
- PrimDouble :: Prim Double
- PrimNByteInteger :: !Int -> Prim Integer

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

# Documentation

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.

PrimWord8 :: Prim Word8 | |

PrimWord16 :: Prim Word16 | |

PrimWord32 :: Prim Word32 | |

PrimWord64 :: Prim Word64 | |

PrimDouble :: Prim Double | |

PrimNByteInteger :: !Int -> Prim Integer |

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" `Prim`

s, and a (possibly partial)
function that maps those `Prim`

s to implementations, derives a total function
mapping all `Prim`

s 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.