cchalmers / pcg-random

Haskell interface to the pcg random number generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Function suggestion: withFrozen

akhra opened this issue · comments

The pure System.Random interface is nice, but still considerably slower than working within the pcg-random idiom. Chasing an alternative, I've come up with this:

withFrozen :: (Variate a)
           => (forall s. Gen s -> ST s a) -> FrozenGen -> (a, FrozenGen)
withFrozen f g = runST $ flip runStateT g $ do
  gen <- get >>= \frozen -> restore frozen
  x <- lift $ f gen
  save gen >>= \frozen -> put frozen
  return x

By way of example, I've also got a function

roll :: (PrimMonad m) => Int -> Gen (PrimState m) -> m Int

and it works with either withFrozen (roll n) g or withSystemRandom $ roll n.

I'm sketchy on the order of arguments -- I also had the idea of working this into a StateT variant, but putting the function last would be more convenient in a lot of cases -- and make no guarantees as to my code being anywhere close to optimal, but it does work and it's MUCH faster than the System.Random interface.

Yeah, the System.Random interface is unfortunately very slow because of how the class is defined. There's a GSOC project that will hopefully fix this.

There's no need for StateT here, it's simply:

withFrozen :: (forall s. Gen s -> ST s a) -> FrozenGen -> (a, FrozenGen)
withFrozen f s = runST $ do
  g  <- restore s
  a  <- f g
  s' <- save g
  return (a, s')

or even

withFrozen f s = runST $ restore s >>= \g -> liftA2 (,) (f g) (save g)

which I'll add.

I've actually started a pure branch here which performs faster than using ST. I couldn't figure out a nice interface and since I only use the ST version I've just left it until the GSOC project comes.

Added in aa5b482. I decided to flip the arguments.

My predictions of suboptimality have yet to come up short. ;) Ed Kmett brought up GSOC yesterday on #haskell-game too, sounds like there's real momentum there.